Synapse can do callbacks at several tactical places. This way you can trace opening or closing of the socket, log errors, or count the amount of data transferred.
This all happens in one callback handler.
Assigning the callback handler is relatively easy. First, you will have to define a callback procedure, we will talk about that later.
Then you assign the callback to a TBlockSocket descendant. Protocol implementations all have their sock property public or published.
like this:
sock := TTCPBlockSocket.Create; sock.OnStatus := SockCallBack;
or
HTTP := THTTPSend.Create; HTTP.Sock.OnStatus := SockCallBack;
This is the definition of the callback function:
THookSocketStatus = procedure(Sender: TObject; Reason: THookSocketReason; const Value: string) of object;
Define SockCallBack? as follow:
TMyObject = class (TObject) //..your other declarations procedure SockCallBack (Sender: TObject; Reason: THookSocketReason; const Value: string); end;
! Please note: Value is declared as string, but mostly contains an integer value. You can use StrToIntDef(Value, -1) to retrieve the value.
THookSocketReason is defined as follows:
THookSocketReason = ( HR_ResolvingBegin, HR_ResolvingEnd, HR_SocketCreate, HR_SocketClose, HR_Bind, HR_Connect, HR_CanRead, HR_CanWrite, HR_Listen, HR_Accept, HR_ReadCount, HR_WriteCount, HR_Wait, HR_Error );
Based on the value, you know what the event is.
Note: Some protocols like FTP using more then jist one socket. Be sure that you are monitoring right socket. For example, if you wish to monitor FTP data stransfers, hook TFtpSend.DSock.Onstatus.
How To Put An Callback With An Abstract Object?
For some applications, like a quick-and-dirty non-oops console application, you can define an abstract object with a class function attached and use it as callback handler.
This application (a plugin for the gpu distributed computing over a p2p network project) uses this technique, code below is extracted from this application: http://cvs.sourceforge.net/viewcvs.py/gpu/gpu_solar/src/dllbuilding/earthsim/earthsim.dpr?rev=1.1.1.1&view=markup
uses ..., typinfo; //declaration of a class with one class method: type callback = class class procedure Status (Sender: TObject; Reason: THookSocketReason; const Value: String); end; //implementation class procedure callback.Status(Sender: TObject; Reason: THookSocketReason; const Value: String); var v: String; begin if (reason=hr_readcount) or (reason=hr_writecount) or (reason=hr_canread) then exit; v := getEnumName (typeinfo(THookSocketReason), integer(Reason)) + ' ' + Value; writeln (v); end;
attaching this callback to a socket:
Sock := T[UDP/TCP/..]BlockSocket.Create; Sock.OnStatus := callback.Status;
Hope this helps you out.