Wrap socket Read + Write calls in try except to convert exceptions into a SockErr booleanproperty.

This commit is contained in:
ccrause 2021-07-09 22:12:14 +02:00
parent e0dea1ca30
commit 50e7383718

View File

@ -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;