Changeset 411 for PinConnection/UCommTelnet.pas
- Timestamp:
- Aug 16, 2012, 9:54:23 AM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
PinConnection/UCommTelnet.pas
r408 r411 48 48 TTelnetOption = class 49 49 private 50 FActive: Boolean; 50 51 FOnRequest: TTelnetOptionEvent; 52 protected 53 procedure SetActive(AValue: Boolean); virtual; 51 54 public 52 55 Telnet: TCommTelnet; 53 Code: TTelnet Option;56 Code: TTelnetCommand; 54 57 ServerChecked: Boolean; 55 ServerSupport: Boolean; 58 SupportedByServer: Boolean; 59 function CheckOption: Boolean; 60 procedure SendCommand(Request, Response: TListByte); 56 61 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); 60 66 61 67 { TCommTelnet } … … 63 69 TCommTelnet = class 64 70 private 71 FResponses: TListObject; // TListObject<TListByte> 72 FActive: Boolean; 65 73 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; 69 80 public 70 81 Options: TListObject; … … 72 83 RawPin: TCommPin; 73 84 Timeout: TDateTime; 85 PortType: TTelnetPortType; 86 ErrorCount: Integer; 74 87 procedure Register(Option: TTelnetOption); 75 88 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); 78 92 procedure SendCommand(Code: TTelnetCode; Request, Response: TListByte); 79 93 constructor Create; 80 94 destructor Destroy; override; 95 property Active: Boolean read FActive write SetActive; 81 96 end; 82 97 … … 87 102 SUnknownState = 'Unknown state'; 88 103 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 111 procedure TTelnetOption.SetActive(AValue: Boolean); 112 begin 113 if FActive = AValue then Exit; 114 FActive := AValue; 115 end; 116 117 function TTelnetOption.CheckOption: Boolean; 118 var 119 RequestData: TBinarySerializer; 120 ResponseData: TBinarySerializer; 121 begin 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; 141 end; 142 143 procedure TTelnetOption.SendCommand(Request, Response: TListByte); 144 var 145 RequestData: TBinarySerializer; 146 ResponseData: TBinarySerializer; 147 I: Integer; 148 begin 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; 169 end; 89 170 90 171 { TCommTelnet } 91 172 92 procedure TCommTelnet.TelnetDataReceive(Sender: TCommPin; Stream: T Stream);173 procedure TCommTelnet.TelnetDataReceive(Sender: TCommPin; Stream: TListByte); 93 174 var 94 175 Data: Byte; 95 176 RawData: TBinarySerializer; 177 I: Integer; 96 178 begin 97 179 try … … 99 181 RawData.List := TListByte.Create; 100 182 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]; 104 185 if Data = Byte(tcIAC) then begin 105 186 RawData.WriteByte(Byte(tcIAC)); … … 113 194 end; 114 195 115 procedure TCommTelnet.RawDataReceive(Sender: TCommPin; Stream: TStream); 196 procedure TCommTelnet.SetActive(AValue: Boolean); 197 var 198 I: Integer; 199 begin 200 if FActive = AValue then Exit; 201 FActive := AValue; 202 for I := 0 to Options.Count - 1 do 203 TTelnetOption(Options[I]).Active := AValue; 204 end; 205 206 procedure TCommTelnet.RawDataReceive(Sender: TCommPin; Stream: TListByte); 116 207 var 117 208 Data: Byte; 118 209 RawData: TBinarySerializer; 210 I: Integer; 119 211 begin 120 212 try … … 123 215 RawData.OwnsList := True; 124 216 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]; 128 219 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); 131 224 end else 132 225 if FState = tsIAC then begin 133 226 if Data = Byte(tcSB) then begin 227 // Subnegotation 228 FCommandData.WriteByte(Data); 134 229 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 138 234 FCommandData.WriteByte(Data); 139 235 FState := tsOption; 140 236 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 142 242 FCommandData.WriteByte(Data); 143 FState := tsOption; 243 FResponses.AddNew(TListByte.Create); 244 TListByte(FResponses.Last).Assign(FCommandData.List); FState := tsNormal; 144 245 end else 145 if Data = Byte(tcWONT) then begin 146 FCommandData.WriteByte(Data); 147 FState := tsOption; 148 end else FState := tsNormal; 246 FState := tsNormal; 149 247 end else 150 248 if FState = tsSB then begin 249 // Data inside subnegotation 151 250 if Data = Byte(tcIAC) then FState := tsSB_IAC 152 else FCommandData.WriteByte(Data);251 else FCommandData.WriteByte(Data); 153 252 end else 154 253 if FState = tsSB_IAC then begin 254 // End of subnegotation data 155 255 if Data = Byte(tcSE) then begin 256 FResponses.AddNew(TListByte.Create); 257 TListByte(FResponses.Last).Assign(FCommandData.List); 156 258 FState := tsNormal; 157 end else 158 259 end else begin 260 Inc(ErrorCount); 261 FState := tsNormal; 262 end; 159 263 end else 160 264 if FState = tsOption then begin 265 // Third byte of negotation 161 266 FCommandData.WriteByte(Data); 267 FResponses.AddNew(TListByte.Create); 268 TListByte(FResponses.Last).Assign(FCommandData.List); 162 269 FState := tsNormal; 163 270 end else raise Exception.Create(SUnknownState); … … 169 276 end; 170 277 278 procedure TCommTelnet.ReadResponse(Response: TListByte); 279 var 280 TimeStart: TDateTime; 281 ElapsedTime: TDateTime; 282 begin 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); 291 end; 292 293 function TCommTelnet.ResponseCount: Integer; 294 begin 295 Result := FResponses.Count; 296 end; 297 171 298 procedure TCommTelnet.Register(Option: TTelnetOption); 172 299 begin … … 180 307 end; 181 308 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, 309 function TCommTelnet.CheckOption(OptionCode: TTelnetCommand): Boolean; 310 var 311 Option: TTelnetOption; 312 begin 313 Option := SearchOption(OptionCode); 314 if Assigned(Option) then Result := Option.CheckOption 315 else raise Exception.Create(SOptionNotFound); 316 end; 317 318 function TCommTelnet.SearchOption(OptionCode: TTelnetCommand): TTelnetOption; 319 var 320 I: Integer; 321 begin 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; 327 end; 328 329 procedure TCommTelnet.SendSubCommand(OptionCode: TTelnetCommand; Request, 199 330 Response: TListByte); 200 331 var 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; 333 begin 334 Option := SearchOption(OptionCode); 335 if Assigned(Option) then Option.SendCommand(Request, Response) 336 else raise Exception.Create(SOptionNotFound); 224 337 end; 225 338 … … 228 341 var 229 342 Data: TBinarySerializer; 343 LastIAC: Boolean; 344 I: Integer; 230 345 begin 231 346 try … … 235 350 Data.WriteByte(Byte(tcIAC)); 236 351 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; 237 360 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; 241 386 finally 242 387 Data.Free; … … 246 391 constructor TCommTelnet.Create; 247 392 begin 248 FCommandData := TStreamHelper.Create; 393 FResponses := TListObject.Create; 394 FCommandData := TBinarySerializer.Create; 395 FCommandData.List := TListByte.Create; 396 FCommandData.OwnsList := True; 249 397 TelnetPin := TCommPin.Create; 398 TelnetPin.OnReceive := TelnetDataReceive; 250 399 RawPin := TCommPin.Create; 400 RawPin.OnReceive := RawDataReceive; 251 401 Options := TListObject.Create; 402 Options.OwnsObjects := False; 252 403 Timeout := 2 * OneSecond; 253 404 end; … … 259 410 TelnetPin.Free; 260 411 RawPin.Free; 412 FResponses.Free; 261 413 inherited Destroy; 262 414 end;
Note:
See TracChangeset
for help on using the changeset viewer.