mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-15 18:19:07 +02:00
Wrap socket Read + Write calls in try except to convert exceptions into a SockErr booleanproperty.
This commit is contained in:
parent
e0dea1ca30
commit
50e7383718
@ -70,12 +70,19 @@ type
|
|||||||
fCS: TRTLCriticalSection;
|
fCS: TRTLCriticalSection;
|
||||||
FFileName: string;
|
FFileName: string;
|
||||||
FOwner: TDbgProcess;
|
FOwner: TDbgProcess;
|
||||||
|
// Catch exceptions and store as socket errors
|
||||||
|
FSockErr: boolean;
|
||||||
procedure FSetRegisterCacheSize(sz: cardinal);
|
procedure FSetRegisterCacheSize(sz: cardinal);
|
||||||
procedure FResetStatusEvent;
|
procedure FResetStatusEvent;
|
||||||
// Blocking
|
// Blocking
|
||||||
function FWaitForData(): boolean; overload;
|
function FWaitForData(): boolean; overload;
|
||||||
function FWaitForData(timeout_ms: integer): boolean; overload;
|
function FWaitForData(timeout_ms: integer): boolean; overload;
|
||||||
|
|
||||||
|
// Wrappers to catch exceptions and set SockErr
|
||||||
|
function SafeReadByte: byte;
|
||||||
|
function SafeWrite(const buffer; count : Longint): Longint;
|
||||||
|
procedure SafeWriteByte(b: Byte);
|
||||||
|
|
||||||
function FReadReply(out retval: string): boolean;
|
function FReadReply(out retval: string): boolean;
|
||||||
function FSendCommand(const cmd: string): boolean;
|
function FSendCommand(const cmd: string): boolean;
|
||||||
// Send command and wait for acknowledge
|
// Send command and wait for acknowledge
|
||||||
@ -122,6 +129,7 @@ type
|
|||||||
property State: integer read FState;
|
property State: integer read FState;
|
||||||
property RegisterCacheSize: cardinal write FSetRegisterCacheSize;
|
property RegisterCacheSize: cardinal write FSetRegisterCacheSize;
|
||||||
property lastStatusEvent: TStatusEvent read FStatusEvent;
|
property lastStatusEvent: TStatusEvent read FStatusEvent;
|
||||||
|
property SockErr: boolean read FSockErr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
@ -177,6 +185,7 @@ var
|
|||||||
{$endif}
|
{$endif}
|
||||||
begin
|
begin
|
||||||
Result:=False;
|
Result:=False;
|
||||||
|
if SockErr then exit;
|
||||||
{$if defined(unix)}
|
{$if defined(unix)}
|
||||||
FDS := Default(TFDSet);
|
FDS := Default(TFDSet);
|
||||||
fpFD_Zero(FDS);
|
fpFD_Zero(FDS);
|
||||||
@ -203,6 +212,7 @@ var
|
|||||||
{$endif}
|
{$endif}
|
||||||
begin
|
begin
|
||||||
Result:=False;
|
Result:=False;
|
||||||
|
if SockErr then exit;
|
||||||
//{$if defined(unix) or defined(windows)}
|
//{$if defined(unix) or defined(windows)}
|
||||||
TimeV.tv_usec := timeout_ms * 1000; // 1 msec
|
TimeV.tv_usec := timeout_ms * 1000; // 1 msec
|
||||||
TimeV.tv_sec := 0;
|
TimeV.tv_sec := 0;
|
||||||
@ -222,32 +232,55 @@ begin
|
|||||||
{$endif}
|
{$endif}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TRspConnection.SafeReadByte: byte;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
Result := ReadByte;
|
||||||
|
except
|
||||||
|
FSockErr := true;
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRspConnection.SafeWrite(const buffer; count: Longint): Longint;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
Result := Write(buffer, count);
|
||||||
|
except
|
||||||
|
FSockErr := true;
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TRspConnection.SafeWriteByte(b: Byte);
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
WriteByte(b);
|
||||||
|
except
|
||||||
|
FSockErr := true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TRspConnection.FSendCommand(const cmd: string): boolean;
|
function TRspConnection.FSendCommand(const cmd: string): boolean;
|
||||||
var
|
var
|
||||||
checksum: byte;
|
checksum: byte;
|
||||||
i, totalSent: integer;
|
i, totalSent: integer;
|
||||||
s: string;
|
s: string;
|
||||||
begin
|
begin
|
||||||
|
Result := false;
|
||||||
|
if SockErr then exit;
|
||||||
checksum := 0;
|
checksum := 0;
|
||||||
for i := 1 to length(cmd) do
|
for i := 1 to length(cmd) do
|
||||||
checksum := byte(checksum + ord(cmd[i]));
|
checksum := byte(checksum + ord(cmd[i]));
|
||||||
|
|
||||||
s := '$'+cmd+'#'+IntToHex(checksum, 2);
|
s := '$'+cmd+'#'+IntToHex(checksum, 2);
|
||||||
totalSent := Write(s[1], length(s));
|
totalSent := SafeWrite(s[1], length(s));
|
||||||
|
|
||||||
// Debugging
|
|
||||||
//system.WriteLn(s);
|
|
||||||
|
|
||||||
result := (totalSent = length(s));
|
result := (totalSent = length(s));
|
||||||
if not result then
|
if not result then
|
||||||
begin
|
|
||||||
//WriteLn('* FSendRspCommand error');
|
|
||||||
DebugLn(DBG_WARNINGS, ['Warning: TRspConnection.FSendRspCommand error.'])
|
DebugLn(DBG_WARNINGS, ['Warning: TRspConnection.FSendRspCommand error.'])
|
||||||
end
|
|
||||||
else
|
else
|
||||||
begin
|
|
||||||
DebugLn(DBG_RSP, ['RSP -> ', cmd]);
|
DebugLn(DBG_RSP, ['RSP -> ', cmd]);
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TRspConnection.FSendCommandOK(const cmd: string): boolean;
|
function TRspConnection.FSendCommandOK(const cmd: string): boolean;
|
||||||
@ -256,6 +289,7 @@ var
|
|||||||
retryCount: integer;
|
retryCount: integer;
|
||||||
begin
|
begin
|
||||||
result := false;
|
result := false;
|
||||||
|
if SockErr then exit;
|
||||||
retryCount := 0;
|
retryCount := 0;
|
||||||
|
|
||||||
repeat
|
repeat
|
||||||
@ -263,7 +297,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
// now check if target returned error, resend ('-') or ACK ('+')
|
// now check if target returned error, resend ('-') or ACK ('+')
|
||||||
// No support for ‘QStartNoAckMode’, i.e. always expect a -/+
|
// No support for ‘QStartNoAckMode’, i.e. always expect a -/+
|
||||||
c := char(ReadByte);
|
c := char(SafeReadByte);
|
||||||
result := c = '+';
|
result := c = '+';
|
||||||
if not result then
|
if not result then
|
||||||
inc(retryCount);
|
inc(retryCount);
|
||||||
@ -271,7 +305,7 @@ begin
|
|||||||
else
|
else
|
||||||
inc(retryCount);
|
inc(retryCount);
|
||||||
// Abort this command if no ACK after 5 attempts
|
// Abort this command if no ACK after 5 attempts
|
||||||
until result or (retryCount > 5);
|
until result or (retryCount > 5) or SockErr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TRspConnection.FReadReply(out retval: string): boolean;
|
function TRspConnection.FReadReply(out retval: string): boolean;
|
||||||
@ -282,30 +316,29 @@ var
|
|||||||
i: integer;
|
i: integer;
|
||||||
cksum, calcSum: byte;
|
cksum, calcSum: byte;
|
||||||
begin
|
begin
|
||||||
|
Result := false;
|
||||||
|
if SockErr then exit;
|
||||||
i := 0;
|
i := 0;
|
||||||
s := '';
|
s := '';
|
||||||
//IOTimeout := 10; // sometimes an empty response needs to be swallowed to
|
|
||||||
repeat
|
repeat
|
||||||
c := chr(ReadByte);
|
c := chr(SafeReadByte);
|
||||||
inc(i);
|
inc(i);
|
||||||
s := s + c;
|
s := s + c;
|
||||||
until (c = '$') or (i = failcountmax); // exit loop after start or count expired
|
until (c = '$') or (i = failcountmax) or SockErr; // exit loop after start or count expired
|
||||||
|
|
||||||
if c <> '$' then
|
if c <> '$' then
|
||||||
begin
|
begin
|
||||||
//WriteLn('* Timeout waiting for RSP reply');
|
|
||||||
DebugLn(DBG_WARNINGS, ['Warning: Timeout waiting for RSP reply']);
|
DebugLn(DBG_WARNINGS, ['Warning: Timeout waiting for RSP reply']);
|
||||||
result := false;
|
result := false;
|
||||||
retval := '';
|
retval := '';
|
||||||
exit;
|
exit;
|
||||||
end
|
end
|
||||||
else if i > 1 then
|
else if i > 1 then
|
||||||
begin
|
DebugLn(DBG_WARNINGS, ['Warning: Discarding unexpected data before start of new message', s])
|
||||||
//WriteLn('* Discarding data before start of message: ', s);
|
else if SockErr then
|
||||||
DebugLn(DBG_WARNINGS, ['Warning: Discarding unexpected data before start of new message', s]);
|
DebugLn(DBG_WARNINGS, ['Warning: socket error.']);
|
||||||
end;
|
|
||||||
|
|
||||||
c := chr(ReadByte);
|
c := chr(SafeReadByte);
|
||||||
s := '';
|
s := '';
|
||||||
calcSum := 0;
|
calcSum := 0;
|
||||||
while c <> '#' do
|
while c <> '#' do
|
||||||
@ -314,12 +347,11 @@ begin
|
|||||||
|
|
||||||
if c=#$7D then // escape marker, unescape data
|
if c=#$7D then // escape marker, unescape data
|
||||||
begin
|
begin
|
||||||
c := char(ReadByte);
|
c := char(SafeReadByte);
|
||||||
|
|
||||||
// Something weird happened
|
// Something weird happened
|
||||||
if c = '#' then
|
if c = '#' then
|
||||||
begin
|
begin
|
||||||
//WriteLn('* Received end of packet marker in escaped sequence: ', c);
|
|
||||||
DebugLn(DBG_WARNINGS, ['Warning: Received end of packet marker in escaped sequence: ', c]);
|
DebugLn(DBG_WARNINGS, ['Warning: Received end of packet marker in escaped sequence: ', c]);
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
@ -330,22 +362,20 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
s := s + c;
|
s := s + c;
|
||||||
c := char(ReadByte);
|
c := char(SafeReadByte);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
cksum := StrToInt('$' + char(ReadByte) + char(ReadByte));
|
cksum := StrToInt('$' + char(SafeReadByte) + char(SafeReadByte));
|
||||||
|
|
||||||
// Ignore checksum for now
|
// Ignore checksum for now
|
||||||
WriteByte(byte('+'));
|
SafeWriteByte(byte('+'));
|
||||||
result := true;
|
result := not SockErr;
|
||||||
retval := s;
|
retval := s;
|
||||||
if not (calcSum = cksum) then
|
if not (calcSum = cksum) then
|
||||||
begin
|
begin
|
||||||
//WriteLn('* Reply packet with invalid checksum: ', s);
|
|
||||||
DebugLn(DBG_WARNINGS, ['Warning: Reply packet with invalid checksum: ', s]);
|
DebugLn(DBG_WARNINGS, ['Warning: Reply packet with invalid checksum: ', s]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
//WriteLn('RSP <- ', retval);
|
|
||||||
DebugLn(DBG_RSP, ['RSP <- ', retval]);
|
DebugLn(DBG_RSP, ['RSP <- ', retval]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -355,6 +385,7 @@ var
|
|||||||
retryCount: integer;
|
retryCount: integer;
|
||||||
begin
|
begin
|
||||||
reply := '';
|
reply := '';
|
||||||
|
if SockErr then exit;
|
||||||
retryCount := 0;
|
retryCount := 0;
|
||||||
|
|
||||||
if FSendCommandOK(cmd) then
|
if FSendCommandOK(cmd) then
|
||||||
@ -365,9 +396,9 @@ begin
|
|||||||
if not result then
|
if not result then
|
||||||
begin
|
begin
|
||||||
inc(retryCount);
|
inc(retryCount);
|
||||||
WriteByte(ord('-'));
|
SafeWriteByte(ord('-'));
|
||||||
end;
|
end;
|
||||||
until result or (retryCount > 5);
|
until result or (retryCount > 5) or SockErr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if retryCount > 5 then
|
if retryCount > 5 then
|
||||||
@ -430,7 +461,7 @@ procedure TRspConnection.Break();
|
|||||||
begin
|
begin
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
WriteByte(3); // Ctrl-C
|
SafeWriteByte(3); // Ctrl-C
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
@ -444,14 +475,14 @@ begin
|
|||||||
try
|
try
|
||||||
result := FSendCommand('k');
|
result := FSendCommand('k');
|
||||||
// Swallow the last ack if send
|
// Swallow the last ack if send
|
||||||
result := FWaitForData(1000);
|
result := not(SockErr) and FWaitForData(1000);
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if result then
|
if result then
|
||||||
begin
|
begin
|
||||||
c := char(ReadByte);
|
c := char(SafeReadByte);
|
||||||
Result := c = '+';
|
Result := c = '+';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -466,7 +497,7 @@ begin
|
|||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
result := pos('OK', reply) = 1;
|
result := not(SockErr) and (pos('OK', reply) = 1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
constructor TRspConnection.Create(AFileName: string; AOwner: TDbgProcess);
|
constructor TRspConnection.Create(AFileName: string; AOwner: TDbgProcess);
|
||||||
@ -481,6 +512,7 @@ begin
|
|||||||
InitCriticalSection(fCS);
|
InitCriticalSection(fCS);
|
||||||
FFileName := AFileName;
|
FFileName := AFileName;
|
||||||
FOwner := AOwner;
|
FOwner := AOwner;
|
||||||
|
FSockErr := false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TRspConnection.Destroy;
|
destructor TRspConnection.Destroy;
|
||||||
@ -609,7 +641,7 @@ begin
|
|||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
result := reply = '';
|
result := not(SockErr) and (reply = '');
|
||||||
if not result then
|
if not result then
|
||||||
DebugLn(DBG_WARNINGS, ['Warning: vMustReplyEmpty command returned unexpected result: ', reply]);
|
DebugLn(DBG_WARNINGS, ['Warning: vMustReplyEmpty command returned unexpected result: ', reply]);
|
||||||
end;
|
end;
|
||||||
@ -630,7 +662,7 @@ begin
|
|||||||
|
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
result := FSendCmdWaitForReply(cmd, reply);
|
result := FSendCmdWaitForReply(cmd, reply) and not(SockErr);
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
@ -654,7 +686,7 @@ begin
|
|||||||
|
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
result := FSendCmdWaitForReply(cmd, reply);
|
result := FSendCmdWaitForReply(cmd, reply) and not(SockErr);
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
@ -667,7 +699,7 @@ begin
|
|||||||
DebugLn(DBG_VERBOSE, ['TRspConnection.Continue() called']);
|
DebugLn(DBG_VERBOSE, ['TRspConnection.Continue() called']);
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
result := FSendCommandOK('c');
|
result := FSendCommandOK('c') and not(SockErr);
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
@ -679,7 +711,7 @@ function TRspConnection.SingleStep(): boolean;
|
|||||||
begin
|
begin
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
result := FSendCommandOK('s');
|
result := FSendCommandOK('s') and not(SockErr);
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
@ -695,7 +727,7 @@ begin
|
|||||||
cmd := 'p'+IntToHex(ind, 2);
|
cmd := 'p'+IntToHex(ind, 2);
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
result := FSendCmdWaitForReply(cmd, reply);
|
result := FSendCmdWaitForReply(cmd, reply) and not(SockErr);
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
@ -740,9 +772,9 @@ begin
|
|||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
|
Result := Result and not(SockErr);
|
||||||
if Result then
|
if Result then
|
||||||
begin
|
begin
|
||||||
//WriteLn('Read registers reply: ', reply);
|
|
||||||
for i := 0 to sz-1 do
|
for i := 0 to sz-1 do
|
||||||
b[i] := StrToInt('$'+reply[2*i+1]+reply[2*i+2]);
|
b[i] := StrToInt('$'+reply[2*i+1]+reply[2*i+2]);
|
||||||
result := true;
|
result := true;
|
||||||
@ -778,7 +810,7 @@ begin
|
|||||||
// Normal receive error, or an error number of the form Exx
|
// Normal receive error, or an error number of the form Exx
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
result := FSendCmdWaitForReply(cmd, reply) and (reply = 'OK');
|
result := FSendCmdWaitForReply(cmd, reply) and (reply = 'OK') and not(SockErr);
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
@ -798,7 +830,7 @@ begin
|
|||||||
cmd := 'm'+IntToHex(AAddress, 2)+',' + IntToHex(ASize, 2);
|
cmd := 'm'+IntToHex(AAddress, 2)+',' + IntToHex(ASize, 2);
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
result := FSendCmdWaitForReply(cmd, reply) and (length(reply) = ASize*2);
|
result := FSendCmdWaitForReply(cmd, reply) and (length(reply) = ASize*2) and not(SockErr);
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
@ -839,7 +871,7 @@ begin
|
|||||||
|
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
result := FSendCmdWaitForReply(cmd, reply) and (reply = 'OK');
|
result := FSendCmdWaitForReply(cmd, reply) and (reply = 'OK') and not(SockErr);
|
||||||
finally
|
finally
|
||||||
LeaveCriticalSection(fCS);
|
LeaveCriticalSection(fCS);
|
||||||
end;
|
end;
|
||||||
@ -852,7 +884,7 @@ var
|
|||||||
cmdstr, reply: string;
|
cmdstr, reply: string;
|
||||||
begin
|
begin
|
||||||
cmdstr := 'qRcmd,' + FHexEncodeStr(s);
|
cmdstr := 'qRcmd,' + FHexEncodeStr(s);
|
||||||
result := FSendCmdWaitForReply(cmdstr, reply);
|
result := FSendCmdWaitForReply(cmdstr, reply) and not(SockErr);
|
||||||
|
|
||||||
// Check if reply is not hex encoded, else decode reply
|
// Check if reply is not hex encoded, else decode reply
|
||||||
if Result and not((reply = '') or (reply = 'OK') or ((length(reply) = 3) and (reply[1] = 'E'))) then
|
if Result and not((reply = '') or (reply = 'OK') or ((length(reply) = 3) and (reply[1] = 'E'))) then
|
||||||
@ -877,7 +909,7 @@ begin
|
|||||||
reply := '';
|
reply := '';
|
||||||
EnterCriticalSection(fCS);
|
EnterCriticalSection(fCS);
|
||||||
try
|
try
|
||||||
if not FSendCmdWaitForReply('vMustReplyEmpty', reply) or (reply <> '') then
|
if not FSendCmdWaitForReply('vMustReplyEmpty', reply) or (reply <> '') or SockErr then
|
||||||
begin
|
begin
|
||||||
DebugLn(DBG_WARNINGS, ['Warning: vMustReplyEmpty command returned unexpected result: ', reply]);
|
DebugLn(DBG_WARNINGS, ['Warning: vMustReplyEmpty command returned unexpected result: ', reply]);
|
||||||
exit;
|
exit;
|
||||||
|
Loading…
Reference in New Issue
Block a user