Ignore:
Timestamp:
Aug 16, 2012, 9:54:23 AM (12 years ago)
Author:
chronos
Message:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • PinConnection/UCommTelnet.pas

    r408 r411  
    4848  TTelnetOption = class
    4949  private
     50    FActive: Boolean;
    5051    FOnRequest: TTelnetOptionEvent;
     52  protected
     53    procedure SetActive(AValue: Boolean); virtual;
    5154  public
    5255    Telnet: TCommTelnet;
    53     Code: TTelnetOption;
     56    Code: TTelnetCommand;
    5457    ServerChecked: Boolean;
    55     ServerSupport: Boolean;
     58    SupportedByServer: Boolean;
     59    function CheckOption: Boolean;
     60    procedure SendCommand(Request, Response: TListByte);
    5661    property OnRequest: TTelnetOptionEvent read FOnRequest write FOnRequest;
    57   end;
    58 
    59   { TTelnetOptionList }
     62    property Active: Boolean read FActive write SetActive;
     63  end;
     64
     65  TTelnetPortType = (ptClient, ptServer);
    6066
    6167  { TCommTelnet }
     
    6369  TCommTelnet = class
    6470  private
     71    FResponses: TListObject; // TListObject<TListByte>
     72    FActive: Boolean;
    6573    FState: TTelnetState;
    66     FCommandData: TStreamHelper;
    67     procedure TelnetDataReceive(Sender: TCommPin; Stream: TStream);
    68     procedure RawDataReceive(Sender: TCommPin; Stream: TStream);
     74    FCommandData: TBinarySerializer;
     75    procedure SetActive(AValue: Boolean);
     76    procedure TelnetDataReceive(Sender: TCommPin; Stream: TListByte);
     77    procedure RawDataReceive(Sender: TCommPin; Stream: TListByte);
     78    procedure ReadResponse(Response: TListByte);
     79    function ResponseCount: Integer;
    6980  public
    7081    Options: TListObject;
     
    7283    RawPin: TCommPin;
    7384    Timeout: TDateTime;
     85    PortType: TTelnetPortType;
     86    ErrorCount: Integer;
    7487    procedure Register(Option: TTelnetOption);
    7588    procedure Unregister(Option: TTelnetOption);
    76     function CheckOption(Option: TTelnetCommand): Boolean;
    77     procedure SendSubCommand(Option: TTelnetCommand; Request, Response: TListByte);
     89    function CheckOption(OptionCode: TTelnetCommand): Boolean;
     90    function SearchOption(OptionCode: TTelnetCommand): TTelnetOption;
     91    procedure SendSubCommand(OptionCode: TTelnetCommand; Request, Response: TListByte);
    7892    procedure SendCommand(Code: TTelnetCode; Request, Response: TListByte);
    7993    constructor Create;
    8094    destructor Destroy; override;
     95    property Active: Boolean read FActive write SetActive;
    8196  end;
    8297
     
    87102  SUnknownState = 'Unknown state';
    88103  SWrongResponseOption = 'Wrong response option';
     104  SWrongResponseCode = 'Wrong response code';
     105  SWrongResponse = 'Wrong response';
     106  SOptionNotFound = 'Option not found';
     107  STimeout = 'Telnet command timout';
     108
     109{ TTelnetOption }
     110
     111procedure TTelnetOption.SetActive(AValue: Boolean);
     112begin
     113  if FActive = AValue then Exit;
     114  FActive := AValue;
     115end;
     116
     117function TTelnetOption.CheckOption: Boolean;
     118var
     119  RequestData: TBinarySerializer;
     120  ResponseData: TBinarySerializer;
     121begin
     122  if not ServerChecked then
     123  try
     124    RequestData := TBinarySerializer.Create;
     125    RequestData.List := TListByte.Create;
     126    RequestData.OwnsList := True;
     127    ResponseData := TBinarySerializer.Create;
     128    ResponseData.List := TListByte.Create;
     129    ResponseData.OwnsList := True;
     130
     131    RequestData.WriteByte(Byte(Code));
     132    Telnet.SendCommand(tcDo, RequestData.List, ResponseData.List);
     133    if ResponseData.List[0] = Byte(tcWILL) then SupportedByServer := True
     134      else if ResponseData.List[0] = Byte(tcWONT) then SupportedByServer := False
     135      else raise Exception.Create(SWrongResponse);
     136    ServerChecked := True;
     137  finally
     138    RequestData.Free;
     139    RequestData.Free;
     140  end;
     141end;
     142
     143procedure TTelnetOption.SendCommand(Request, Response: TListByte);
     144var
     145  RequestData: TBinarySerializer;
     146  ResponseData: TBinarySerializer;
     147  I: Integer;
     148begin
     149  CheckOption;
     150  try
     151    RequestData := TBinarySerializer.Create;
     152    RequestData.List := TListByte.Create;
     153    RequestData.OwnsList := True;
     154    ResponseData := TBinarySerializer.Create;
     155    ResponseData.List := TListByte.Create;
     156    ResponseData.OwnsList := True;
     157
     158    RequestData.WriteByte(Byte(Code));
     159    RequestData.WriteList(Request, 0, Request.Count);
     160    Telnet.SendCommand(tcSB, RequestData.List, ResponseData.List);
     161    if ResponseData.List[0] <> Byte(Code) then
     162      raise Exception.Create(SWrongResponseOption);
     163    ResponseData.List.Delete(0);
     164    Response.Assign(ResponseData.List);
     165  finally
     166    RequestData.Free;
     167    RequestData.Free;
     168  end;
     169end;
    89170
    90171{ TCommTelnet }
    91172
    92 procedure TCommTelnet.TelnetDataReceive(Sender: TCommPin; Stream: TStream);
     173procedure TCommTelnet.TelnetDataReceive(Sender: TCommPin; Stream: TListByte);
    93174var
    94175  Data: Byte;
    95176  RawData: TBinarySerializer;
     177  I: Integer;
    96178begin
    97179  try
     
    99181    RawData.List := TListByte.Create;
    100182    RawData.OwnsList := True;
    101     Stream.Position := 0;
    102     while Stream.Position < Stream.Size do begin
    103       Data := Stream.ReadByte;
     183    for I := 0 to Stream.Count - 1 do begin
     184      Data := Stream[I];
    104185      if Data = Byte(tcIAC) then begin
    105186        RawData.WriteByte(Byte(tcIAC));
     
    113194end;
    114195
    115 procedure TCommTelnet.RawDataReceive(Sender: TCommPin; Stream: TStream);
     196procedure TCommTelnet.SetActive(AValue: Boolean);
     197var
     198  I: Integer;
     199begin
     200  if FActive = AValue then Exit;
     201  FActive := AValue;
     202  for I := 0 to Options.Count - 1 do
     203    TTelnetOption(Options[I]).Active := AValue;
     204end;
     205
     206procedure TCommTelnet.RawDataReceive(Sender: TCommPin; Stream: TListByte);
    116207var
    117208  Data: Byte;
    118209  RawData: TBinarySerializer;
     210  I: Integer;
    119211begin
    120212  try
     
    123215    RawData.OwnsList := True;
    124216
    125     Stream.Position := 0;
    126     while Stream.Position < Stream.Size do begin
    127       Data := Stream.ReadByte;
     217    for I := 0 to Stream.Count - 1 do begin
     218      Data := Stream[I];
    128219      if FState = tsNormal then begin
    129         if Data = Byte(tcIAC) then FState := tsIAC
    130           else RawData.WriteByte(Data);
     220        if Data = Byte(tcIAC) then begin
     221          FCommandData.Clear;
     222          FState := tsIAC;
     223        end else RawData.WriteByte(Data);
    131224      end else
    132225      if FState = tsIAC then begin
    133226        if Data = Byte(tcSB) then begin
     227          // Subnegotation
     228          FCommandData.WriteByte(Data);
    134229          FState := tsSB;
    135           FCommandData.Size := 0;
    136         end
    137         else if Data = Byte(tcDO) then begin
     230        end else
     231        if (Data = Byte(tcWILL)) or (Data = Byte(tcDONT)) or (Data = Byte(tcWONT)) or (Data = Byte(tcDO))
     232        then begin
     233          // Three byte negotation commands
    138234          FCommandData.WriteByte(Data);
    139235          FState := tsOption;
    140236        end else
    141         if Data = Byte(tcDONT) then begin
     237        if (Data = Byte(tcAYT)) or (Data = Byte(tcNOP)) or (Data = Byte(tcGA)) or
     238        (Data = Byte(tcEL)) or (Data = Byte(tcEC)) or (Data = Byte(tcAO)) or
     239        (Data = Byte(tcIP)) or (Data = Byte(tcBREAK)) or (Data = Byte(tcDATA_MARK)) or
     240        (Data = Byte(tcEOR)) then begin
     241          // Two byte commands
    142242          FCommandData.WriteByte(Data);
    143           FState := tsOption;
     243          FResponses.AddNew(TListByte.Create);
     244          TListByte(FResponses.Last).Assign(FCommandData.List);         FState := tsNormal;
    144245        end else
    145         if Data = Byte(tcWONT) then begin
    146           FCommandData.WriteByte(Data);
    147           FState := tsOption;
    148         end else FState := tsNormal;
     246          FState := tsNormal;
    149247      end else
    150248      if FState = tsSB then begin
     249        // Data inside subnegotation
    151250        if Data = Byte(tcIAC) then FState := tsSB_IAC
    152         else FCommandData.WriteByte(Data);
     251          else FCommandData.WriteByte(Data);
    153252      end else
    154253      if FState = tsSB_IAC then begin
     254        // End of subnegotation data
    155255        if Data = Byte(tcSE) then begin
     256          FResponses.AddNew(TListByte.Create);
     257          TListByte(FResponses.Last).Assign(FCommandData.List);
    156258          FState := tsNormal;
    157         end else
    158 
     259        end else begin
     260          Inc(ErrorCount);
     261          FState := tsNormal;
     262        end;
    159263      end else
    160264      if FState = tsOption then begin
     265        // Third byte of negotation
    161266        FCommandData.WriteByte(Data);
     267        FResponses.AddNew(TListByte.Create);
     268        TListByte(FResponses.Last).Assign(FCommandData.List);
    162269        FState := tsNormal;
    163270      end else raise Exception.Create(SUnknownState);
     
    169276end;
    170277
     278procedure TCommTelnet.ReadResponse(Response: TListByte);
     279var
     280  TimeStart: TDateTime;
     281  ElapsedTime: TDateTime;
     282begin
     283  TimeStart := Now;
     284  repeat
     285    ElapsedTime := Now - TimeStart;
     286  until (ElapsedTime > Timeout) or (ResponseCount > 0);
     287  if ElapsedTime > Timeout then
     288    raise Exception.Create(STimeout);
     289  Response.Assign(TListByte(FResponses.First));
     290  FResponses.Delete(0);
     291end;
     292
     293function TCommTelnet.ResponseCount: Integer;
     294begin
     295  Result := FResponses.Count;
     296end;
     297
    171298procedure TCommTelnet.Register(Option: TTelnetOption);
    172299begin
     
    180307end;
    181308
    182 function TCommTelnet.CheckOption(Option: TTelnetCommand): Boolean;
    183 var
    184   Data: TBinarySerializer;
    185 begin
    186   try
    187     Data := TBinarySerializer.Create;
    188     Data.List := TListByte.Create;
    189     Data.OwnsList := True;
    190     Data.WriteByte(Byte(tcWILL));
    191     Data.WriteByte(Byte(Option));
    192     RawPin.Send(Data.List);
    193   finally
    194     Data.Free;
    195   end;
    196 end;
    197 
    198 procedure TCommTelnet.SendSubCommand(Option: TTelnetCommand; Request,
     309function TCommTelnet.CheckOption(OptionCode: TTelnetCommand): Boolean;
     310var
     311  Option: TTelnetOption;
     312begin
     313  Option := SearchOption(OptionCode);
     314  if Assigned(Option) then Result := Option.CheckOption
     315    else raise Exception.Create(SOptionNotFound);
     316end;
     317
     318function TCommTelnet.SearchOption(OptionCode: TTelnetCommand): TTelnetOption;
     319var
     320  I: Integer;
     321begin
     322  I := 0;
     323  while (I < Options.Count) and (TTelnetOption(Options[I]).Code <> OptionCode) do
     324    Inc(I);
     325  if I < Options.Count then Result := TTelnetOption(Options[I])
     326    else Result := nil;
     327end;
     328
     329procedure TCommTelnet.SendSubCommand(OptionCode: TTelnetCommand; Request,
    199330  Response: TListByte);
    200331var
    201   RequestData: TBinarySerializer;
    202   ResponseData: TBinarySerializer;
    203 begin
    204   try
    205     RequestData := TBinarySerializer.Create;
    206     RequestData.List := TListByte.Create;
    207     RequestData.OwnsList := True;
    208     ResponseData := TBinarySerializer.Create;
    209     ResponseData.List := TListByte.Create;
    210     ResponseData.OwnsList := True;
    211 
    212     RequestData.WriteByte(Byte(Option));
    213     RequestData.WriteList(Request, 0, Request.Count);
    214     RequestData.WriteByte(Byte(tcIAC));
    215     RequestData.WriteByte(Byte(tcSE));
    216     SendCommand(tcSB, RequestData.List, ResponseData.List);
    217     ResponseData.Position := 0;
    218     if ResponseData.ReadByte <> Byte(Option) then
    219       raise Exception.Create(SWrongResponseOption);
    220   finally
    221     RequestData.Free;
    222     RequestData.Free;
    223   end;
     332  Option: TTelnetOption;
     333begin
     334  Option := SearchOption(OptionCode);
     335  if Assigned(Option) then Option.SendCommand(Request, Response)
     336    else raise Exception.Create(SOptionNotFound);
    224337end;
    225338
     
    228341var
    229342  Data: TBinarySerializer;
     343  LastIAC: Boolean;
     344  I: Integer;
    230345begin
    231346  try
     
    235350    Data.WriteByte(Byte(tcIAC));
    236351    Data.WriteByte(Byte(Code));
     352    for I := 0 to Request.Count - 1 do begin
     353      if Request[I] = Byte(tcIAC) then Data.WriteByte(Byte(tcIAC));
     354      Data.WriteByte(Request[I]);
     355    end;
     356    if Code = tcSB then begin
     357      Data.WriteByte(Byte(tcIAC));
     358      Data.WriteByte(Byte(tcSE));
     359    end;
    237360    RawPin.Send(Data.List);
    238 //    repeat
    239 
    240 //    until ;
     361    if Assigned(Response) then begin
     362      ReadResponse(Response);
     363      if Response[0] <> Byte(Code) then
     364        raise Exception.Create(SWrongResponseCode);
     365      Response.Delete(0);
     366      if Code = tcSB then begin
     367        if (Response[Response.Count - 2] <> Byte(tcIAC)) or
     368        (Response[Response.Count - 1] <> Byte(tcSE)) then
     369          raise Exception.Create(SWrongResponse);
     370        Response.DeleteItems(Response.Count - 2, 2);
     371      end;
     372      // Remove IAC escape character from data
     373      I := 0;
     374      while (I < Response.Count) do begin
     375        if Response[I] = Byte(tcIAC) then begin
     376          if not LastIAC then LastIAC := True
     377          else begin
     378            LastIAC := False;
     379            Response.Delete(I);
     380            Dec(I);
     381          end;
     382        end;
     383        Inc(I);
     384      end;
     385    end;
    241386  finally
    242387    Data.Free;
     
    246391constructor TCommTelnet.Create;
    247392begin
    248   FCommandData := TStreamHelper.Create;
     393  FResponses := TListObject.Create;
     394  FCommandData := TBinarySerializer.Create;
     395  FCommandData.List := TListByte.Create;
     396  FCommandData.OwnsList := True;
    249397  TelnetPin := TCommPin.Create;
     398  TelnetPin.OnReceive := TelnetDataReceive;
    250399  RawPin := TCommPin.Create;
     400  RawPin.OnReceive := RawDataReceive;
    251401  Options := TListObject.Create;
     402  Options.OwnsObjects := False;
    252403  Timeout := 2 * OneSecond;
    253404end;
     
    259410  TelnetPin.Free;
    260411  RawPin.Free;
     412  FResponses.Free;
    261413  inherited Destroy;
    262414end;
Note: See TracChangeset for help on using the changeset viewer.