📄 awwnsock.pas
字号:
if FOptSupga <> tnoNegotiating then begin
if DefOptSupga then begin
SendDo(Option);
end else begin
SendDont(Option);
end;
end else begin
FOptSupga := tnoTrue;
end;
end;
TELNETOPT_ECHO :
begin
if FOptEcho <> tnoNegotiating then begin
if DefOptEcho then begin
SendDo(Option);
end else begin
SendDont(Option);
end;
end else begin
FOptEcho := tnoTrue;
end;
end else begin
SendDont(Option);
end;
end;
end else begin
Result := False;
if FDispatcher.DLoggingOn then
FDispatcher.AddDispatchEntry(dtTelnet, dstCommand, Ord(Command), nil, 0);
end;
end;
end;
{ Process & strip telnet commands -- calling method is responsible for }
{ ensuring there is at least Size bytes left in the Dest buffer }
function TWsConnection.ProcessCommands(Dest : PChar; Size : Cardinal) : Integer;
var
StartDest, EndBuf, Temp : PChar;
function NextChar : Char;
begin
if (FInCursor + 1) = FInBufEnd then
Result := FInBuf^
else
Result := (FInCursor + 1)^;
end;
begin
StartDest := Dest;
EndBuf := FInCursor + Size;
while FInCursor < EndBuf do begin
if FInCursor^ <> TELNET_IAC then begin
{ ASCII mode, and CR/NULL received -- strip the null }
if (FOptBinary = tnoFalse) and (FInCursor^ = TELNET_CR) and
(NextChar = TELNET_NULL) then begin
Dest^ := FInCursor^;
Dest := Dest + 1;
FInCursor := FInCursor + 2;
if FInCursor > FinBufEnd then begin
FInCursor := FInBuf + 1;
Break;
end;
end else begin
{ Copy over verbatim }
Dest^ := FInCursor^;
FInCursor := FInCursor + 1;
Dest := Dest + 1;
end;
end else begin
if ((FInCursor + 1) = FInBufEnd) and (FInEnd = FInBuf) then
break;
if NextChar = TELNET_IAC then begin
{ It's an escaped IAC -- copy a single over }
Dest^ := FInCursor^;
Dest := Dest + 1;
FInCursor := FInCursor + 2;
if FInCursor > FinBufEnd then begin
FInCursor := FInBuf + 1;
break;
end;
end else begin
{ If at the end of the buffer, and made it this far, exit loop }
if (FInCursor + 1) = FInBufEnd then begin
FInCursor := FInCursor + 1;
Break;
end;
if NextChar <> TELNET_SB then begin
{ It's an actual command -- strip it and act on it }
if HandleCommand((FInCursor + 1)^, (FInCursor + 2)^) then
FInCursor := FInCursor + 3
else
FInCursor := FInCursor + 2;
end else begin
{ It's a subnegotation situation -- look for the end }
if (FInCursor + 2)^ = TELNETOPT_TERM then
SendTerminal;
Temp := FindIAC((FInCursor + 1), EndBuf - (FInCursor + 1));
if (Temp + 1)^ = TELNET_SE then
FInCursor := Temp + 2;
end;
end;
end;
end;
Result := (Dest - StartDest);
end;
{ Read from Winsock and process telnet commands if applicable }
function TWsConnection.ReadBuf(var Buf; Size : Integer) : Integer;
var
NumRead,
NumRead2 : Integer;
CanRead,
CanRead2 : Cardinal;
{$IFDEF Win32}
function MinCard(C1, C2 : Cardinal) : Cardinal; assembler;
asm
cmp eax,edx
jbe @1
mov eax,edx
@1:
end;
{$ELSE}
function MinCard(C1, C2 : Cardinal) : Cardinal; assembler;
asm
mov ax,C1
mov bx,C2
cmp ax,bx
jbe @1
mov ax,bx
@1:
end;
{$ENDIF}
procedure UpDatePtr(var SPtr : PChar; Delta : Integer);
begin
SPtr := SPtr + Delta;
if SPtr >= FInBufEnd then
SPtr := FInBuf + (SPtr - FInBufEnd);
end;
procedure MoveChunk(BeginPt, EndPt : PChar);
var
CanMove : Cardinal;
begin
CanMove := (EndPt - BeginPt);
CanMove := MinCard(CanMove, (Size - Result));
Move(BeginPt^, (PChar(@Buf)+Result)^, CanMove);
Inc(Result, CanMove);
if CanMove > 0 then begin
UpDatePtr(FInStart, CanMove);
if FInStart >= FInBufEnd then
FInStart := FInBuf;
end;
if (FInStart <> FInEnd) or (CanMove > 0) then
FInBufFull := False;
if FInStart <= FInEnd then
if (FInCursor < FInStart) or (FInCursor >= FInEnd) then
FInCursor := FInStart
else
else
if (FInCursor < FInStart) and (FInCursor >= FInEnd) then
FInCursor := FInStart;
end;
procedure ProcessChunk(BuffEnd : Boolean);
var
CanMove, Processed : Cardinal;
EndPt, ResetPt : PChar;
begin
if BuffEnd then begin
EndPt := FInBufEnd;
ResetPt := FInBuf;
end else begin
EndPt := FInEnd;
ResetPt := FInEnd;
end;
CanMove := MinCard((EndPt - FInCursor), (Size - Result));
if CanMove > 0 then begin
Processed := ProcessCommands(PChar(@Buf)+Result, CanMove);
Inc(Result, Processed);
if FInCursor >= EndPt then
FInCursor := ResetPt;
FInStart := FInCursor;
FInBufFull := False;
end;
end;
begin
Result := 0;
if (FInEnd >= FInStart) and not FInBufFull then begin
{ Not currently wrapped -- but we can if need be }
CanRead := (FInBufEnd - FInEnd);
CanRead2 := (FInStart - FInBuf);
NumRead := ApdSocket.ReadSocket(FCommSocket, FInEnd^, CanRead, 0);
if NumRead = SOCKET_ERROR then
NumRead := 0;
if NumRead > 0 then begin
FInEnd := FInEnd + NumRead;
if FInEnd = FInBufEnd then
FInEnd := FInBuf;
if FInStart = FInEnd then
FInBufFull := True;
end;
if Size = 0 then
Exit;
if NumRead = Integer(CanRead) then begin
{ Try again with wrap -- possibly more to read }
NumRead2 := ApdSocket.ReadSocket(FCommSocket, FInBuf^, CanRead2, 0);
if NumRead2 = SOCKET_ERROR then
NumRead2 := 0;
if NumRead2 > 0 then begin
FInEnd := FInBuf + NumRead2;
FInBufFull := (FInStart = FInEnd);
end;
if NumRead2 > 0 then begin
{ Successful wrap read }
FInCursor := FindIAC(FInCursor, (FInBufEnd - FInCursor));
{ Are we processing telnet stuff? }
if FInCursor = FInBufEnd then begin
{ No IACs found }
FInCursor := FInBuf;
MoveChunk(FInStart, FInBufEnd);
end else begin
{ Move data prior to IAC }
MoveChunk(FInStart, FInCursor);
{ Process and move beyond IAC }
ProcessChunk(True);
if FInCursor <> FInBuf then
Exit;
end;
{ Ready to process wrapped data }
FInCursor := FindIAC(FInCursor, (FInEnd - FInCursor));
{ Are we processing telnet stuff? }
if FInCursor = FInEnd then begin
{ No IACs found }
FInCursor := FInStart;
MoveChunk(FInBuf, FInEnd);
end else begin
{ Move data prior to IAC }
MoveChunk(FInBuf, FInCursor);
{ Process and move beyond IAC }
ProcessChunk(False);
end;
end else begin
{ We didn't wrap }
FInCursor := FindIAC(FInCursor, (FInEnd - FInCursor));
{ Are we processing telnet stuff? }
if FInCursor = FInEnd then begin
{ No IACs found }
FInCursor := FInStart;
MoveChunk(FInStart, FInEnd);
end else begin
{ Move data prior to IAC }
MoveChunk(FInStart, FInCursor);
{ Process and move beyond IAC }
ProcessChunk(False);
end;
end;
end else begin
{ Read all there was available -- no need to wrap }
FInCursor := FindIAC(FInCursor, (FInEnd - FInCursor));
{ Are we processing telnet stuff? }
if FInCursor = FInEnd then begin
{ No IACs found }
FInCursor := FInStart;
MoveChunk(FInStart, FInEnd);
end else begin
{ Move data prior to IAC }
MoveChunk(FInStart, FInCursor);
{ Process and move beyond IAC }
ProcessChunk(False);
end;
end;
end else begin
{ Already wrapped }
if not FInBufFull then begin
{ Read as much as we can }
CanRead := (FInStart - FInEnd);
NumRead := ApdSocket.ReadSocket(FCommSocket, FInEnd^, CanRead, 0);
if NumRead = SOCKET_ERROR then
NumRead := 0;
FInEnd := FInEnd + NumRead;
if FInEnd = FInBufEnd then
FInEnd := FInBuf;
if (NumRead > 0) and (FInStart = FInEnd) then
FInBufFull := True;
end;
if Size = 0 then
Exit;
{ Is the cursor on the first half or second half of wrap? }
if FInCursor >= FInStart then begin
{ Yes, cursor is on first half }
FInCursor := FindIAC(FInCursor, (FInBufEnd - FInCursor));
if FInCursor = FInBufEnd then begin
{ No IACs found }
FInCursor := FInStart;
MoveChunk(FInStart, FInBufEnd);
if (FInStart <> FInEnd) then
FInBufFull := False;
FInCursor := FInStart;
end else begin
{ Move data prior to IAC }
MoveChunk(FInStart, FInCursor);
{ Process and move beyond IAC }
ProcessChunk(True);
if (FInStart <> FInEnd) then
FInBufFull := False;
FInCursor := FInStart;
end;
end else begin
{ Cursor is on second half }
FInCursor := FindIAC(FInCursor, (FInEnd - FInCursor));
{ Move first half }
MoveChunk(FInStart, FInBufEnd);
{ Process second half up to IAC }
MoveChunk(FInBuf, FInCursor);
end;
end;
end;
destructor TWsConnection.Destroy;
begin
FreeMem(FInBuf, FInSize);
FreeMem(FOutBuf, FOutSize);
inherited Destroy;
end;
function TWsConnection.GetConnected : Boolean;
begin
Result := (ConnectionState = wcsConnected);
end;
{ Get number of characters currently in the input buffer }
function TWsConnection.GetInChars : Cardinal;
var
Buf : Char;
begin
if FInBufFull then
Result := FInSize
else begin
if ConnectionState = wcsConnected then
{ Force a read from Winsock if anything is available }
ReadBuf(Buf, 0);
if FInBufFull then
Result := FInSize
else
if FInEnd >= FInStart then
Result := FInEnd - FInStart
else
Result := LongInt(FInSize) - (FInStart - FInEnd);
end;
end;
{ Get number of characters currently in the output buffer }
function TWsConnection.GetOutChars : Cardinal;
var
Buf : Char;
begin
if (ConnectionState = wcsConnected) then
{ Force a write to Winsock if buffer has data }
if FOutBufFull or (FOutStart <> FOutEnd) then begin
WriteBuf(Buf, 0);
end else begin
FSimBuf := 0;
end;
Result := FSimBuf;
end;
{ Set the connection state and DCD if necessary }
procedure TWsConnection.SetConnectionState(Value : TWsConnectionState);
begin
if FConnectionState <> Value then begin
if FConnectionState = wcsConnected then
ClearFlag(FDispatcher.ModemStatus, DCDMask);
FConnectionState := Value;
if FConnectionState = wcsConnected then
SetFlag(FDispatcher.ModemStatus, DCDMask);
end;
end;
{ Send Telnet DO command with option }
procedure TWsConnection.SendDo(Option: Char);
var
Buf : array[1..3] of Char;
begin
Buf[1] := TELNET_IAC;
Buf[2] := TELNET_DO;
Buf[3] := Option;
ApdSocket.WriteSocket(FCommSocket, Buf, SizeOf(Buf), 0);
if FDispatcher.DLoggingOn then
FDispatcher.AddDispatchEntry(dtTelnet, dstSDo, Ord(Option), nil, 0);
end;
{ Send Telnet DONT command with option }
procedure TWsConnection.SendDont(Option: Char);
var
Buf : array[1..3] of Char;
begin
Buf[1] := TELNET_IAC;
Buf[2] := TELNET_DONT;
Buf[3] := Option;
ApdSocket.WriteSocket(FCommSocket, Buf, SizeOf(Buf), 0);
if FDispatcher.DLoggingOn then
FDispatcher.AddDispatchEntry(dtTelnet, dstSDont, Ord(Option), nil, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -