initial commit
[rofl0r-KOL.git] / units / indy / IdTunnelMaster.pas
blobc2d51645d250fd0cdb69e17dbc66d81d5f7d86bb
1 //30-nov-2002
2 unit IdTunnelMaster;
4 interface
5 uses KOL { ,
6 Classes } ,
7 IdTCPServer, IdTCPClient, IdTunnelCommon,
8 SyncObjs;
10 type
11 // TIdTunnelMaster = object(TObj);
12 //PIdTunnelMaster=^TIdTunnelMaster; type MyStupid0=DWord;
14 MClientThread = object(TThread)
15 public
16 MasterParent: PObj;//TIdTunnelMaster;
17 UserId: Integer;
18 MasterThread: TIdPeerThread;
19 OutboundClient: TIdTCPClient;
20 DisconnectedOnRequest: Boolean;
21 Locker: TCriticalSection;
22 SelfDisconnected: Boolean;
23 // procedure Execute; virtual;
25 // override;
26 { constructor Create(master: TIdTunnelMaster);
27 } destructor Destroy;
28 virtual; end;
29 PMClientThread=^MClientThread;
30 function NewMClientThread(master: PObj{TIdTunnelMaster}):PMClientThread;
31 type
33 TSlaveData = object(TObj)
34 public
35 Receiver: TReceiver;
36 Sender: TSender;
37 Locker: TCriticalSection;
38 SelfDisconnected: Boolean;
39 UserData: TObject;
40 end;
41 PSlaveData=^TSlaveData;
42 function NewSlaveData:PSlaveData;
43 type
45 TSendMsgEvent = procedure(Thread: TIdPeerThread; var CustomMsg: string) of
46 object;
47 TSendTrnEvent = procedure(Thread: TIdPeerThread; var Header: TIdHeader; var
48 CustomMsg: string) of object;
49 TSendTrnEventC = procedure(var Header: TIdHeader; var CustomMsg: string) of
50 object;
51 TTunnelEventC = procedure(Receiver: TReceiver) of object;
52 TSendMsgEventC = procedure(var CustomMsg: string) of object;
54 TIdTunnelMaster = object(TIdTCPServer)
55 private
56 fiMappedPort: Integer;
57 fsMappedHost: string;
58 // Clients: TThreadList;
59 { fOnConnect,
60 fOnDisconnect,
61 fOnTransformRead: TIdServerThreadEvent;}
62 fOnTransformSend: TSendTrnEvent;
63 fOnInterpretMsg: TSendMsgEvent;
64 OnlyOneThread: TCriticalSection;
66 StatisticsLocker: TCriticalSection;
67 fbActive: Boolean;
68 fbLockDestinationHost: Boolean;
69 fbLockDestinationPort: Boolean;
70 fLogger: TLogger;
72 flConnectedSlaves,
73 flConnectedServices,
74 fNumberOfConnectionsValue,
75 fNumberOfPacketsValue,
76 fCompressionRatioValue,
77 fCompressedBytes,
78 fBytesRead,
79 fBytesWrite: Integer;
80 procedure ClientOperation(Operation: Integer; UserId: Integer; s: string);
81 procedure SendMsg(MasterThread: TIdPeerThread; var Header: TIdHeader; s:
82 string);
83 procedure DisconectAllUsers;
84 procedure DisconnectAllSubThreads(TunnelThread: TIdPeerThread);
85 function GetNumSlaves: Integer;
86 function GetNumServices: Integer;
87 function GetClientThread(UserID: Integer): MClientThread;
88 protected
89 procedure SetActive(pbValue: Boolean); virtual;//override;
90 procedure DoConnect(Thread: TIdPeerThread); virtual;//override;
91 procedure DoDisconnect(Thread: TIdPeerThread);virtual;// override;
92 function DoExecute(Thread: TIdPeerThread): boolean; virtual;//override;
93 procedure DoTransformRead(Thread: TIdPeerThread); virtual;
94 procedure DoTransformSend(Thread: TIdPeerThread; var Header: TIdHeader; var
95 CustomMsg: string);
96 virtual;
97 procedure DoInterpretMsg(Thread: TIdPeerThread; var CustomMsg: string);
98 virtual;
99 procedure LogEvent(Msg: string);
100 // published
101 property MappedHost: string read fsMappedHost write fsMappedHost;
102 property MappedPort: Integer read fiMappedPort write fiMappedPort;
103 property LockDestinationHost: Boolean read fbLockDestinationHost write
104 fbLockDestinationHost
105 default False;
106 property LockDestinationPort: Boolean read fbLockDestinationPort write
107 fbLockDestinationPort
108 default False;
109 property OnConnect: TIdServerThreadEvent read FOnConnect write FOnConnect;
110 property OnDisconnect: TIdServerThreadEvent read FOnDisconnect write
111 FOnDisconnect;
112 // property OnTransformRead: TIdServerThreadEvent read fOnTransformRead write
113 // fOnTransformRead;
114 property OnTransformSend: TSendTrnEvent read fOnTransformSend write
115 fOnTransformSend;
116 property OnInterpretMsg: TSendMsgEvent read fOnInterpretMsg write
117 fOnInterpretMsg;
118 public
119 property Active: Boolean read FbActive write SetActive default True;
120 property Logger: TLogger read fLogger write fLogger;
121 property NumSlaves: Integer read GetNumSlaves;
122 property NumServices: Integer read GetNumServices;
123 procedure SetStatistics(Module: Integer; Value: Integer);
124 procedure GetStatistics(Module: Integer; var Value: Integer);
125 // constructor Create(AOwner: TComponent); override;
126 destructor Destroy; virtual;//override;
127 end;
129 PIdTunnelMaster=^TIdTunnelMaster;
131 function NewIdTunnelMaster(AOwner: PControl):PIdTunnelMaster;
133 implementation
134 uses {KOL, IdException,}
135 IdGlobal, IdStack, IdResourceStrings, SysUtils;
137 { constructor TIdTunnelMaster.Create(AOwner: TComponent);
139 function NewIdTunnelMaster (AOwner: PControl):PIdTunnelMaster;
140 begin
141 New( Result, Create );
142 with Result^ do
143 begin
144 { Clients := TThreadList.Create;
145 inherited Create(AOwner);
146 fbActive := False;
147 flConnectedSlaves := 0;
148 flConnectedServices := 0;
150 fNumberOfConnectionsValue := 0;
151 fNumberOfPacketsValue := 0;
152 fCompressionRatioValue := 0;
153 fCompressedBytes := 0;
154 fBytesRead := 0;
155 fBytesWrite := 0;
157 OnlyOneThread := TCriticalSection.Create;
158 StatisticsLocker := TCriticalSection.Create;}
159 end;
160 end;
162 destructor TIdTunnelMaster.Destroy;
163 // virtual;
164 begin
165 // Logger := nil;
166 Active := False;
167 DisconectAllUsers;
168 inherited Destroy;
170 // Clients.Destroy;
171 OnlyOneThread.Free;
172 StatisticsLocker.Free;
173 end;
175 procedure TIdTunnelMaster.SetActive(pbValue: Boolean);
176 begin
178 if fbActive = pbValue then
179 exit;
181 if pbValue then
182 begin
183 inherited SetActive(True);
185 else
186 begin
187 inherited SetActive(False);
188 DisconectAllUsers;
189 end;
191 fbActive := pbValue;
193 end;
195 procedure TIdTunnelMaster.LogEvent(Msg: string);
196 begin
197 // if Assigned(fLogger) then
198 // fLogger.LogEvent(Msg);
199 end;
201 function TIdTunnelMaster.GetNumSlaves: Integer;
203 ClientsNo: Integer;
204 begin
205 GetStatistics(NumberOfSlavesType, ClientsNo);
206 Result := ClientsNo;
207 end;
209 function TIdTunnelMaster.GetNumServices: Integer;
211 ClientsNo: Integer;
212 begin
213 GetStatistics(NumberOfServicesType, ClientsNo);
214 Result := ClientsNo;
215 end;
217 procedure TIdTunnelMaster.GetStatistics(Module: Integer; var Value: Integer);
218 begin
219 StatisticsLocker.Enter;
221 case Module of
222 NumberOfSlavesType:
223 begin
224 Value := flConnectedSlaves;
225 end;
227 NumberOfServicesType:
228 begin
229 Value := flConnectedServices;
230 end;
232 NumberOfConnectionsType:
233 begin
234 Value := fNumberOfConnectionsValue;
235 end;
237 NumberOfPacketsType:
238 begin
239 Value := fNumberOfPacketsValue;
240 end;
242 CompressionRatioType:
243 begin
244 if fCompressedBytes > 0 then
245 begin
246 Value := Trunc((fBytesRead * 1.0) / (fCompressedBytes * 1.0) * 100.0)
248 else
249 begin
250 Value := 0;
251 end;
252 end;
254 CompressedBytesType:
255 begin
256 Value := fCompressedBytes;
257 end;
259 BytesReadType:
260 begin
261 Value := fBytesRead;
262 end;
264 BytesWriteType:
265 begin
266 Value := fBytesWrite;
267 end;
268 end;
269 finally
270 StatisticsLocker.Leave;
271 end;
272 end;
274 procedure TIdTunnelMaster.SetStatistics(Module: Integer; Value: Integer);
276 packets: Real;
277 ratio: Real;
278 begin
279 StatisticsLocker.Enter;
281 case Module of
282 NumberOfSlavesType:
283 begin
284 if TIdStatisticsOperation(Value) = soIncrease then
285 begin
286 Inc(flConnectedSlaves);
288 else
289 begin
290 Dec(flConnectedSlaves);
291 end;
292 end;
294 NumberOfServicesType:
295 begin
296 if TIdStatisticsOperation(Value) = soIncrease then
297 begin
298 Inc(flConnectedServices);
299 Inc(fNumberOfConnectionsValue);
301 else
302 begin
303 Dec(flConnectedServices);
304 end;
305 end;
307 NumberOfConnectionsType:
308 begin
309 Inc(fNumberOfConnectionsValue);
310 end;
312 NumberOfPacketsType:
313 begin
314 Inc(fNumberOfPacketsValue);
315 end;
317 CompressionRatioType:
318 begin
319 ratio := fCompressionRatioValue;
320 packets := fNumberOfPacketsValue;
321 ratio := (ratio / 100.0 * (packets - 1.0) + Value / 100.0) / packets;
322 fCompressionRatioValue := Trunc(ratio * 100);
323 end;
325 CompressedBytesType:
326 begin
327 fCompressedBytes := fCompressedBytes + Value;
328 end;
330 BytesReadType:
331 begin
332 fBytesRead := fBytesRead + Value;
333 end;
335 BytesWriteType:
336 begin
337 fBytesWrite := fBytesWrite + Value;
338 end;
339 end;
340 finally
341 StatisticsLocker.Leave;
342 end;
343 end;
345 procedure TIdTunnelMaster.DoConnect(Thread: TIdPeerThread);
346 begin
348 // Thread.Data := TSlaveData.Create;
349 { with TSlaveData(Thread.Data) do
350 begin
351 Receiver := TReceiver.Create;
352 Sender := TSender.Create;
353 SelfDisconnected := False;
354 Locker := TCriticalSection.Create;
355 end;
356 if Assigned(OnConnect) then
357 begin
358 OnConnect(Thread);
359 end;
360 SetStatistics(NumberOfSlavesType, Integer(soIncrease));
362 end;
364 procedure TIdTunnelMaster.DoDisconnect(Thread: TIdPeerThread);
365 begin
367 SetStatistics(NumberOfSlavesType, Integer(soDecrease));
368 DisconnectAllSubThreads(Thread);
369 if Thread.Connection.Connected then
370 Thread.Connection.Disconnect;
372 if Assigned(OnDisconnect) then
373 begin
374 OnDisconnect(Thread);
375 end;
377 { with TSlaveData(Thread.Data) do
378 begin
379 Receiver.Free;
380 Sender.Free;
381 Locker.Free;
382 TSlaveData(Thread.Data).Free;
383 end;}
384 Thread.Data := nil;
386 end;
388 function TIdTunnelMaster.DoExecute(Thread: TIdPeerThread): boolean;
390 user: TSlaveData;
391 clientThread: MClientThread;
392 s: string;
393 ErrorConnecting: Boolean;
394 sIP: string;
395 CustomMsg: string;
396 Header: TIdHeader;
397 begin
398 result := true;
400 // user := TSlaveData(Thread.Data);
401 { if Thread.Connection.Binding.Readable(IdTimeoutInfinite) then
402 begin
403 user.receiver.Data := Thread.Connection.CurrentReadBuffer;
405 SetStatistics(NumberOfPacketsType, 0);
407 while user.receiver.TypeDetected do
408 begin
409 if not (user.receiver.Header.MsgType in [tmData, tmDisconnect, tmConnect,
410 tmCustom]) then
411 begin
412 Thread.Connection.Disconnect;
413 break;
414 end;
416 if user.receiver.NewMessage then
417 begin
418 if user.Receiver.CRCFailed then
419 begin
420 Thread.Connection.Disconnect;
421 break;
422 end;
425 DoTransformRead(Thread);
426 except
427 Thread.Connection.Disconnect;
428 Break;
429 end;
431 case user.Receiver.Header.MsgType of
432 tmError:
433 begin
435 Thread.Connection.Disconnect;
436 break;
437 except
439 end;
440 end;
442 tmData:
443 begin
445 SetString(s, user.Receiver.Msg, user.Receiver.MsgLen);
446 ClientOperation(tmData, user.Receiver.Header.UserId, s);
447 except
449 end;
450 end;
452 tmDisconnect:
453 begin
455 ClientOperation(tmDisconnect, user.Receiver.Header.UserId, '');
456 except
458 end;
459 end;
461 tmConnect:
462 begin
464 clientThread := MClientThread.Create(self);
466 ErrorConnecting := False;
467 with clientThread do
468 begin
469 UserId := user.Receiver.Header.UserId;
470 MasterThread := Thread;
471 OutboundClient := TIdTCPClient.Create(nil);
472 sIP := GStack.TInAddrToString(user.Receiver.Header.IpAddr);
473 if fbLockDestinationHost then
474 begin
475 OutboundClient.Host := fsMappedHost;
476 if fbLockDestinationPort then
477 OutboundClient.Port := fiMappedPort
478 else
479 OutboundClient.Port := user.Receiver.Header.Port;
481 else
482 begin
483 if sIP = '0.0.0.0' then
484 begin
485 OutboundClient.Host := fsMappedHost;
486 OutboundClient.Port := user.Receiver.Header.Port;
488 else
489 begin
490 OutboundClient.Host := sIP;
491 OutboundClient.Port := user.Receiver.Header.Port;
492 end;
493 end;
494 OutboundClient.Connect;
495 end;
496 except
497 ErrorConnecting := True;
498 end;
499 if ErrorConnecting then
500 begin
501 clientThread.Destroy;
503 else
504 begin
505 clientThread.Resume;
506 end;
507 except
509 end;
511 end;
513 tmCustom:
514 begin
515 CustomMsg := '';
516 DoInterpretMsg(Thread, CustomMsg);
517 if Length(CustomMsg) > 0 then
518 begin
519 Header.MsgType := tmCustom;
520 Header.UserId := 0;
521 SendMsg(Thread, Header, CustomMsg);
522 end;
523 end;
525 end;
527 user.Receiver.ShiftData;
530 else
531 break;
533 end;
534 end;}
535 end;
537 procedure TIdTunnelMaster.DoTransformRead(Thread: TIdPeerThread);
538 begin
540 // if Assigned(fOnTransformRead) then
541 // fOnTransformRead(Thread);
543 end;
545 procedure TIdTunnelMaster.DoTransformSend(Thread: TIdPeerThread; var Header:
546 TIdHeader; var CustomMsg: string);
547 begin
549 if Assigned(fOnTransformSend) then
550 fOnTransformSend(Thread, Header, CustomMsg);
552 end;
554 procedure TIdTunnelMaster.DoInterpretMsg(Thread: TIdPeerThread; var CustomMsg:
555 string);
556 begin
558 if Assigned(fOnInterpretMsg) then
559 fOnInterpretMsg(Thread, CustomMsg);
561 end;
563 procedure TIdTunnelMaster.DisconnectAllSubThreads(TunnelThread: TIdPeerThread);
565 Thread: MClientThread;
566 i: integer;
567 listTemp: TList;
568 begin
570 { OnlyOneThread.Enter;
571 listTemp := Clients.LockList;
573 for i := 0 to listTemp.count - 1 do
574 begin
575 if Assigned(listTemp[i]) then
576 begin
577 Thread := MClientThread(listTemp[i]);
578 if Thread.MasterThread = TunnelThread then
579 begin
580 Thread.DisconnectedOnRequest := True;
581 Thread.OutboundClient.Disconnect;
582 end;
583 end;
584 end;
585 finally
586 Clients.UnlockList;
587 OnlyOneThread.Leave;
588 end;
590 end;
592 procedure TIdTunnelMaster.SendMsg(MasterThread: TIdPeerThread; var Header:
593 TIdHeader; s: string);
595 user: TSlaveData;
596 tmpString: string;
597 begin
599 { if Assigned(MasterThread.Data) then
600 begin
602 TSlaveData(MasterThread.Data).Locker.Enter;
604 user := TSlaveData(MasterThread.Data);
606 tmpString := s;
608 DoTransformSend(MasterThread, Header, tmpString);
609 except
610 on E: Exception do
611 begin
612 raise
613 EIdTunnelTransformErrorBeforeSend.Create(RSTunnelTransformErrorBS);
614 end;
615 end;
616 if Header.MsgType = tmError then
617 begin // error ocured in transformation
618 raise
619 EIdTunnelTransformErrorBeforeSend.Create(RSTunnelTransformErrorBS);
620 end;
622 user.Sender.PrepareMsg(Header, PChar(@tmpString[1]), Length(tmpString));
623 MasterThread.Connection.Write(user.Sender.Msg);
624 except
625 raise;
626 end;
627 finally
628 TSlaveData(MasterThread.Data).Locker.Leave;
629 end;
631 end;}
632 end;
634 function TIdTunnelMaster.GetClientThread(UserID: Integer): MClientThread;
636 Thread: MClientThread;
637 i: integer;
638 begin
640 // Result := nil;
641 { with Clients.LockList do
643 for i := 0 to Count - 1 do
644 begin
646 if Assigned(Items[i]) then
647 begin
648 Thread := MClientThread(Items[i]);
649 if Thread.UserId = UserID then
650 begin
651 Result := Thread;
652 break;
653 end;
654 end;
655 except
656 Result := nil;
657 end;
658 end;
659 finally
660 Clients.UnlockList;
661 end;
663 end;
665 procedure TIdTunnelMaster.DisconectAllUsers;
666 begin
667 TerminateAllThreads;
668 end;
670 procedure TIdTunnelMaster.ClientOperation(Operation: Integer; UserId: Integer;
671 s: string);
673 Thread: MClientThread;
674 begin
676 Thread := GetClientThread(UserID);
677 { if Assigned(Thread) then
678 begin
679 Thread.Locker.Enter;
681 if not Thread.SelfDisconnected then
682 begin
683 case Operation of
684 tmData:
685 begin
687 Thread.OutboundClient.CheckForDisconnect;
688 if Thread.OutboundClient.Connected then
689 Thread.OutboundClient.Write(s);
690 except
692 Thread.OutboundClient.Disconnect;
693 except
695 end;
696 end;
697 end;
699 tmDisconnect:
700 begin
701 Thread.DisconnectedOnRequest := True;
703 Thread.OutboundClient.Disconnect;
704 except
706 end;
707 end;
709 end;
711 end;
712 finally
713 Thread.Locker.Leave;
714 end;
715 end;
717 end;
719 { constructor MClientThread.Create(master: TIdTunnelMaster);
721 function NewClientThread (master: TIdTunnelMaster):PMClientThread;
722 begin
723 New( Result, Create );
724 with Result^ do
725 begin
726 // MasterParent := master;
727 // FreeOnTerminate := True;
728 DisconnectedOnRequest := False;
729 SelfDisconnected := False;
730 Locker := TCriticalSection.Create;
731 // MasterParent.Clients.Add(self);
732 master.SetStatistics(NumberOfServicesType, Integer(soIncrease));
734 // inherited Create(True);
735 end;
736 end;
738 destructor MClientThread.Destroy;
739 // virtual;
741 Header: TIdHeader;
742 begin
743 // MasterParent.SetStatistics(NumberOfServicesType, Integer(soDecrease));
745 // MasterParent.Clients.Remove(self);
747 if not DisconnectedOnRequest then
748 begin
750 Header.MsgType := tmDisconnect;
751 Header.UserId := UserId;
752 // MasterParent.SendMsg(MasterThread, Header, RSTunnelDisconnectMsg);
753 except
755 end;
756 end;
758 if OutboundClient.Connected then
759 OutboundClient.Disconnect;
761 except
763 end;
765 // MasterThread := nil;
768 OutboundClient.Free;
769 except
771 end;
773 Locker.Free;
775 Terminate;
777 inherited Destroy;
778 end;
780 {procedure MClientThread.Execute;
782 s: string;
783 Header: TIdHeader;
784 begin
786 while not Terminated do
787 begin
789 if OutboundClient.Connected then
790 begin
791 if OutboundClient.Binding.Readable(IdTimeoutInfinite) then
792 begin
793 s := OutboundClient.CurrentReadBuffer;
795 Header.MsgType := tmData;
796 Header.UserId := UserId;
797 MasterParent.SendMsg(MasterThread, Header, s);
798 except
799 Terminate;
800 break;
801 end;
802 end;
804 else
805 begin
806 Terminate;
807 break;
808 end;
810 end;
811 except
813 end;
815 Locker.Enter;
817 SelfDisconnected := True;
818 finally
819 Locker.Leave;
820 end;
822 end;}
824 function NewMClientThread(master: PObj{TIdTunnelMaster}):PMClientThread;
825 begin
826 New( Result, Create );
827 end;
829 function NewSlaveData:PSlaveData;
830 begin
831 New( Result, Create );
832 end;
834 end.