Mega Code Archive

 
Categories / Delphi / LAN Web TCP
 

Handling Winsock errors

Title: Handling Winsock errors Question: For any of the following exception handling methods to work, the VCL must in some way become aware that an error condition exists. If a call to the Winsock does not return, or does not provide information to the TCustomWinSocket descendant that called it, then there is no mechanism to handle the condition. OnError exception handler. Answer: One method for trapping exception conditions in a descendant of TCustomWinSocket is to use an OnError exception handler. This method will only handle a limited set of conditions because the mechanism provided by the Winsock for event notification only reacts to a limited list of conditions. To be notified of an exception condition within the Winsock, TCustomWinSocket registers user message CM_SocketMessage to be sent to the component, and the CMSocketMessage message handler raises an exception. The message is registered with the Winsock by an API call to WSASyncSelect. WSASyncSelect is a request for event notification of socket read, writes, connect, close, and accept events. If the exception condition is not read, write, connect, close or accept, or if the CM_SocketMessage is not sent by the Winsock for any reason, the error handler will not fire. Usage: procedure TChatForm.ClientSocketError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); const ErrorEvents: array[eeGeneral..eeAccept] of string = ( 'eeGeneral', 'eeSend', 'eeReceive', 'eeConnect', 'eeDisconnect', 'eeAccept' ); begin ListBox1.Items.Add('ClientSocketError. TErrorEvent: ' + ErrorEvents[ErrorEvent] + ' ErrorCode: ' + IntToStr(ErrorCode)); ErrorCode := 0; // don't raise an exception end; Definition: procedure TCustomWinSocket.CMSocketMessage(var Message: TCMSocketMessage); function CheckError: Boolean; var ErrorEvent: TErrorEvent; ErrorCode: Integer; begin if Message.SelectError 0 then begin Result := False; ErrorCode := Message.SelectError; case Message.SelectEvent of FD_CONNECT: ErrorEvent := eeConnect; FD_CLOSE: ErrorEvent := eeDisconnect; FD_READ: ErrorEvent := eeReceive; FD_WRITE: ErrorEvent := eeSend; FD_ACCEPT: ErrorEvent := eeAccept; else ErrorEvent := eeGeneral; end; Error(Self, ErrorEvent, ErrorCode); if ErrorCode 0 then raise ESocketError.CreateFmt(sASyncSocketError, [ErrorCode]); end else Result := True; end; begin with Message do if CheckError then case SelectEvent of FD_CONNECT: Connect(Socket); FD_CLOSE: Disconnect(Socket); FD_READ: Read(Socket); FD_WRITE: Write(Socket); FD_ACCEPT: Accept(Socket); end; end; Object Pascal Exception Handling You can also wrap a specific call in a try..except block or setting an application level exception handler. For this to work, the component must in some way become aware of the exception condition and an exception must be raised for the exception to be trapped here. Example of Application Exception Handler: TChatForm = class(TForm) . . public procedure AppException(Sender: TObject; E: Exception); end; . . implementation . . procedure TChatForm.AppException(Sender: TObject; E: Exception); begin ListBox1.Items.Add('AppException: ' + E.Message); end; procedure TChatForm.FormCreate(Sender: TObject); begin Application.OnException := AppException; end; Example of Try..Except block: with ClientSocket do try Active := True; except on E: Exception do ListBox1.Items.Add('Try..except during open: ' + E.Message); end; end; SocketErrorProc For calls that use the CheckSocketResult function to check the result returned by WSAGetLastError, errors can be handled in a programmer defined function by setting the SocketErrorProc. Usage: Interface . . procedure MySocketError(ErrorCode: Integer); implementation . . procedure MySocketError(ErrorCode: Integer); begin ShowMessage('MySocketError: ' + IntToStr(ErrorCode)); end; procedure TChatForm.FormCreate(Sender: TObject); begin SocketErrorProc := MySocketError; end; Defined: function CheckSocketResult(ResultCode: Integer; const Op: string): Integer; begin if ResultCode 0 then begin Result := WSAGetLastError; if Result WSAEWOULDBLOCK then if Assigned(SocketErrorProc) then SocketErrorProc(Result) else raise ESocketError.CreateFmt(sWindowsSocketError, [SysErrorMessage(Result), Result, Op]); end else Result := 0; end; Help Text for SocketErrorProc: Unit ScktComp SocketErrorProc handles error messages that are received from a Windows socket connection. threadvar SocketErrorProc: procedure (ErrorCode: Integer); Assign a value to SocketErrorProc to handle error messages from Windows socket API calls before the socket component raises an exception. Setting SocketErrorProc prevents the socket component from raising an exception. SocketErrorProc is a thread-local variable. It only handles errors that arise from the Windows socket API calls made within a single execution thread.