•  

ГлавнаяIndyЧастые вопросы по Indy → Хочу перезагрузить модем посредством связи через telnet, использую компонент idTelnet

Создано: 17.05.2014 3:48:21 · Исправлено: 17.05.2014 3:48:21 · Прочтений: 1832

Хочу перезагрузить модем посредством связи через telnet, использую компонент
TidTelnet
(indy), модем D-Link 500T. Вот код:
begin
  idTelnet1.Connect;
  idTelnet1.SendCmd(admin);
  idTelnet1.SendCmd(password);
  idTelnet1.SendCmd(reboot);
  idTelnet1.Disconnect;
end;


Дело в том, что когда я вызываю его в программе, то данные передаются на модем (лампочка моргает), но самой перезагрузки нет. Пробую отлаживать - работает! То есть нужно дожидаться ответа или вставлять паузу, что ни есть хорошо (не по русски как-то повставлять везде
sleep(9000)
). Подскажите пожалуйста как это сделать.
ЗЫ
Метод SendCmd для этого компонента является функцией, а то есть она возвращает значение, так вот: присваивание этого значения (я так понимаю сигнал о корректном завершении своей работы) переменной целого типа не помогло!
Пробовал:
  idTelnet1.Connect;
  if idTelnet1.Connected then
    begin
      for i:=1 to 3 do
        begin
          for j:=1 to Length(Commands[i]) do
            idTelnet1.SendCh(Commands[i][j]);
          idTelnet1.SendCh(#13);
        end;
      idTelnet1.Disconnect;
    end;

Тоже самое!
Я тоже пробовал reboot - не пашет во многих мопедах, 2540 в т.ч. Просто отваливается телнет сервер а мопед работает дальше. Поработав с FreeBSD я нашел прикол, что когда прибиваешь инит командой kill 1, то происходит очень шустрая перезагрузка с ошибкой Attemp to shutdown init process. Т.к. в этих мопедах юзается mLinux, то трюк пашет и на них. 100%. Вот мой код службы - ребутилки (более подробно здесь>http://forum.pavlodar.us/viewtopic.php?f=2&t=2271]здесь):

unit RebooterServiceU;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
  ExtCtrls, Ping, Registry, IniFiles,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdTelnet;

type
  TROKeeper = class(TService)
    DoTimer: TTimer;
    Telnet: TIdTelnet;
    procedure ServiceAfterInstall(Sender: TService);
    procedure ServiceAfterUninstall(Sender: TService);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure DoTimerTimer(Sender: TObject);
  private
    { Private declarations }
  public
    function  GetServiceController: TServiceController; override;
  end;

var
  ROKeeper: TROKeeper;
  TimerInterval:dword;
  Threshold:integer;
  ModemName,ModemUser,ModemPass:string;
  ModemPrompt:char;
  Hosts:array[0..9] of string;

implementation

{$R *.DFM}
{$R msg.res}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  ROKeeper.Controller(CtrlCode);
end;

function TROKeeper.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;
{======================================================================}
{Создание лога}
procedure TROKeeper.ServiceAfterInstall(Sender: TService);
var Reg: TRegIniFile;
    SysRoot:string;
begin
    Reg := TRegIniFile.Create(KEY_ALL_ACCESS);
    try
      Reg.RootKey := HKEY_LOCAL_MACHINE;
      // Создаём ссистемный журнал для ексепшинов
//      Reg.OpenKey(\SYSTEM\CurrentControlSet\Services\Eventlog\Application\ + Name, True);
//      Reg.WriteString(\SYSTEM\CurrentControlSet\Services\Eventlog\Application\ + Name, EventMessageFile, ParamStr(0));
//      TRegistry(Reg).WriteInteger(TypesSupported, 7);
      // Создаём свой журнал
      SysRoot:=Reg.ReadString(\SOFTWARE\Microsoft\Windows NT\CurrentVersion\,SystemRoot,C:\WINDOWS);
      Reg.OpenKey(\SYSTEM\CurrentControlSet\Services\Eventlog\+Name, True);
      Reg.WriteString(\SYSTEM\CurrentControlSet\Services\Eventlog\+Name+\, DisplayNameFile, ParamStr(0));
      Reg.WriteString(\SYSTEM\CurrentControlSet\Services\Eventlog\+Name+\, Sources, Name);
      Reg.WriteString(\SYSTEM\CurrentControlSet\Services\Eventlog\+Name+\, PrimaryModule, Name);
      Reg.WriteString(\SYSTEM\CurrentControlSet\Services\Eventlog\+Name+\, File, SysRoot+\system32\config\+Name+.Evt);
      TRegistry(Reg).WriteInteger(DisplayNameID,1);
      Reg.OpenKey(\SYSTEM\CurrentControlSet\Services\Eventlog\+Name+\ + Name, True);
      Reg.WriteString(\SYSTEM\CurrentControlSet\Services\Eventlog\+Name+\ + Name, EventMessageFile, ParamStr(0));
      TRegistry(Reg).WriteInteger(TypesSupported, 7);
      // Прописываем себе описание
      Reg.WriteString(\SYSTEM\CurrentControlSet\Services\ + Name, Description, Служба перезагрузки роутера при потере соединения с провайдером.);
    finally
      FreeAndNil(Reg);
    end;
end;
{Удаление лога}
procedure TROKeeper.ServiceAfterUninstall(Sender: TService);
var Reg: TRegIniFile;
begin
    Reg := TRegIniFile.Create(KEY_ALL_ACCESS);
    try
      Reg.RootKey := HKEY_LOCAL_MACHINE;
      // Удалим ссистемный журнал
//      Reg.EraseSection(\SYSTEM\CurrentControlSet\Services\Eventlog\Application\ + Name);
      // Удалим свой журнал
      Reg.EraseSection(\SYSTEM\CurrentControlSet\Services\Eventlog\+Name+\ + Name);
      Reg.EraseSection(\SYSTEM\CurrentControlSet\Services\Eventlog\+Name+\);
    finally
      FreeAndNil(Reg);
    end;
end;
{Запуск потока службы}
procedure TROKeeper.ServiceStart(Sender: TService;
  var Started: Boolean);
var  Log,Ini,Limiter:string;
    MyINI:TIniFile;
    c,ok:byte;
begin
    Log:=Router On-Line Keeper v3.0+#13+#10+1> Чтение конфигурации...;
    Ini:=ChangeFileExt(ParamStr(0),.INI);
    if FileExists(Ini) then begin ok:=0;
        MyIni:=TIniFile.Create(Ini);
        TimerInterval:=MyIni.ReadInteger(MAIN,TimerInterval,30)*60000;
        Threshold:=MyIni.ReadInteger(MAIN,Threshold,50);
        ModemName:=MyIni.ReadString(MODEM,ModemName,192.168.1.1);
        ModemUser:=MyIni.ReadString(MODEM,ModemUser,admin);
        ModemPass:=MyIni.ReadString(MODEM,ModemPass,admin);
        Limiter:=MyIni.ReadString(MODEM,ModemPrompt,#); ModemPrompt:=Limiter[1];
        for c:=0 to 9 do Hosts[c]:=MyIni.ReadString(HOSTS,Host+IntToStr(c),);
        MyIni.Free;
        for c:=0 to 9 do if Hosts[c]<> then inc(ok);
        if ok>0 then begin
          DoTimer.Interval:=TimerInterval; DoTimer.Enabled:=true;
          LogMessage(Log+#13+#10+2> Служба запущена., EVENTLOG_INFORMATION_TYPE, 0, 0);
          end else LogMessage(Log+#13+#10+2> Не указаны хосты для пинга!, EVENTLOG_ERROR_TYPE, 0, 0);
        end else LogMessage(Log+#13+#10+2> Ошибка чтения INI файла!, EVENTLOG_ERROR_TYPE, 0, 0);
end;
{Останов потока службы}
procedure TROKeeper.ServiceStop(Sender: TService;
  var Stopped: Boolean);
begin
    DoTimer.Enabled:=false;
    LogMessage(Служба остановлена., EVENTLOG_INFORMATION_TYPE, 0, 0);
end;
{Таймер}
procedure TROKeeper.DoTimerTimer(Sender: TObject);
var  Log:string;
    c,ok,pn:byte;
    noerr:boolean;
function WaitForText(Text:string):string;
var  Tmp,Answ:string;
    c:word;
    b:byte;
begin
    Answ:=;
    repeat
      Telnet.ReadBuffer(b,1); Answ:=Answ+Chr(b); Tmp:=;
      if Length(Answ)>Length(Text) then
          for c:=Length(Answ)-Length(Text)+1 to Length(Answ) do Tmp:=Tmp+Answ[c]
          else for c:=1 to Length(Answ) do Tmp:=Tmp+Answ[c];
    until Tmp=Text;
    WaitForText:=Answ;
end;
begin
    Log:=1> Старт сеанса.; noerr:=false;
    if IsIPHostUp(ModemName) then begin ok:=0; pn:=0;
        Log:=Log+#13+#10+2> Модем ответил (+IntToStr(PingTime)+ мс).+#13+#10+3> Пингуем хосты...;
        for c:=0 to 9 do
            if Hosts[c]<> then begin inc(ok);
              if IsIPHostUp(Hosts[c]) then begin inc(pn);
                  Log:=Log+#13+#10+Пинг до +Hosts[c]+ равен +IntToStr(PingTime)+ мс.;
                  end;
              end;
        Log:=Log+#13+#10+Ответило +IntToStr(pn)+ из +IntToStr(ok)+ (;
        ok:=Round(pn/ok*100);
        Log:=Log+IntToStr(ok)+%) хостов, порог установлен на +IntToStr(Threshold)+%;
        if Threshold<=ok then LogMessage(Log+#13+#10+4> Перезагрузка не требуется., EVENTLOG_INFORMATION_TYPE, 0, 0)
          else begin Log:=Log+#13+#10+4> Пинга нет, будем ребутить модем!;
          try
              if Telnet.Connected then Telnet.Disconnect;
              Telnet.Terminal:=VT100; Telnet.Host:=ModemName;
              Telnet.Port:=23; Telnet.Connect;{ Telnet.ClearWriteBuffer;} 
{              if Telnet.Connected then begin}
                Log:=Log+#13+#10+5> Логинимся в модем...+#13+#10+-------------------------------------;
                Log:=Log+#13+#10+WaitForText(ogin:); Telnet.Write(ModemUser+#13);
                Log:=Log+#13+#10+WaitForText(assword:); Telnet.Write(ModemPass+#13);
                Log:=Log+#13+#10+WaitForText(ModemPrompt)+#13+#10+-------------------------------------;
                Telnet.Write(kill 1+#13);
                sleep(1000); noerr:=true;
{                end;}
          finally
              if Telnet.Connected then Telnet.Disconnect;
              if noerr then LogMessage(Log+#13+#10+6> Модем перегружен!, EVENTLOG_WARNING_TYPE, 0, 0)
                      else LogMessage(Log+#13+#10+5> Невозможно подключиться к модему!, EVENTLOG_ERROR_TYPE, 0, 0);
          end;
          end;
        end else LogMessage(Log+#13+#10+2> Модем не ответил!, EVENTLOG_ERROR_TYPE, 0, 0);
end;

end.

Юзает модуль PING:

unit Ping;

interface

uses Windows, SysUtils, WinSock;
var  PingTime:dword;
    LastError:string;

function IsIPHostUp(Address:string):Boolean;

implementation

const
  WS_VERSION_REQD = $101;
  ICMP_SUCCESS = 0;
  ICMP_STATUS_BUFFER_TO_SMALL = 11001;                  // Buffer Too Small
  ICMP_STATUS_DESTINATION_NET_UNREACH = 11002;          // Destination Net Unreachable
  ICMP_STATUS_DESTINATION_HOST_UNREACH = 11003;          // Destination Host Unreachable
  ICMP_STATUS_DESTINATION_PROTOCOL_UNREACH = 11004;      // Destination Protocol Unreachable
  ICMP_STATUS_DESTINATION_PORT_UNREACH = 11005;          // Destination Port Unreachable
  ICMP_STATUS_NO_RESOURCE = 11006;                      // No Resources
  ICMP_STATUS_BAD_OPTION = 11007;                        // Bad Option
  ICMP_STATUS_HARDWARE_ERROR = 11008;                    // Hardware Error
  ICMP_STATUS_LARGE_PACKET = 11009;                      // Packet Too Big
  ICMP_STATUS_REQUEST_TIMED_OUT = 11010;                // Request Timed Out
  ICMP_STATUS_BAD_REQUEST = 11011;                      // Bad Request
  ICMP_STATUS_BAD_ROUTE = 11012;                        // Bad Route
  ICMP_STATUS_TTL_EXPIRED_TRANSIT = 11013;              // TimeToLive Expired Transit
  ICMP_STATUS_TTL_EXPIRED_REASSEMBLY = 11014;            // TimeToLive Expired Reassembly
  ICMP_STATUS_PARAMETER = 11015;                        // Parameter Problem
  ICMP_STATUS_SOURCE_QUENCH = 11016;                    // Source Quench
  ICMP_STATUS_OPTION_TOO_BIG = 11017;                    // Option Too Big
  ICMP_STATUS_BAD_DESTINATION = 11018;                  // Bad Destination
  ICMP_STATUS_NEGOTIATING_IPSEC = 11032;                // Negotiating IPSEC
  ICMP_STATUS_GENERAL_FAILURE = 11050;                  // General Failure

type
  IP_OPTION_INFORMATION = record
  Ttl:Byte;
  Tos:Byte;
  Flags:Byte;
  OptionsSize:Byte;
  OptionsData:DWORD;
  end;

  ICMP_ECHO_REPLY = record
  address:DWORD;
  Status:DWORD;
  RoundTripTime:DWORD;
  DataSize:DWORD;
  Reserved:Integer;
  ptrData:DWORD;
  Options:IP_OPTION_INFORMATION;
  Data:string[250];
  end;

function IcmpCreateFile:DWORD; stdcall; external icmp.dll name IcmpCreateFile;
function IcmpCloseHandle(IcmpHandle:DWORD):DWORD; stdcall; external icmp.dll name IcmpCloseHandle;
function IcmpSendEcho(IcmpHandle,DestinationAddress:DWORD; RequestData:PChar;
  RequestSize,RequestOptions:DWORD; var ReplyBuffer:ICMP_ECHO_REPLY;
  ReplySize,Timeout:DWORD):DWORD; stdcall; external icmp.dll name IcmpSendEcho;

function LookupName(const Name:string):TInAddr;
var HostEnt:PHostEnt; InAddr:TInAddr;
begin
HostEnt:=gethostbyname(PChar(Name));
FillChar(InAddr,SizeOf(InAddr),0);
if HostEnt<>nil then
  begin
  with InAddr,HostEnt^ do
    begin
    S_un_b.s_b1:=h_addr^[0];
    S_un_b.s_b2:=h_addr^[1];
    S_un_b.s_b3:=h_addr^[2];
    S_un_b.s_b4:=h_addr^[3];
    end;
  end;
Result:=InAddr;
end;

function DoPing(sAddress:string; var Reply:ICMP_ECHO_REPLY):LongInt;
var hIcmp:DWORD; lAddress:LongInt; lTimeOut:DWORD; StringToSend:string;
begin
StringToSend:=hello there; // данные для отправки
lTimeOut:=1000; // (мс) ICMP (пинг) таймаут
lAddress:=u_long(LookupName(PChar(sAddress)));
if (lAddress=-1)or(lAddress=0) then // если был IP-адрес строкой то по-другому
  lAddress:=inet_addr(PChar(sAddress));
if (lAddress<>-1)and(lAddress<>0) then
  begin
  hIcmp:=IcmpCreateFile;
  if hIcmp = 0 then Result:=ICMP_STATUS_GENERAL_FAILURE
  else
    begin // пинговать IP
    IcmpSendEcho(hIcmp,lAddress,PChar(StringToSend),
      Length(StringToSend),0,Reply,SizeOf(Reply),lTimeOut);
    Result:=Reply.Status; // требуемый статус ответа
    if Result=ICMP_SUCCESS then PingTime:=Reply.RoundTripTime
                            else PingTime:=0;
    IcmpCloseHandle(hIcmp);
    end;
  end
else Result:=ICMP_STATUS_DESTINATION_HOST_UNREACH;
end;

function EvaluatePingResponse(PingResponse:DWORD):string;
begin
case PingResponse of
  // Success
  ICMP_SUCCESS: EvaluatePingResponse:=Success!;
  // Some error occurred
  ICMP_STATUS_BUFFER_TO_SMALL: EvaluatePingResponse:=Buffer Too Small;
  ICMP_STATUS_DESTINATION_NET_UNREACH: EvaluatePingResponse:=Destination Net Unreachable;
  ICMP_STATUS_DESTINATION_HOST_UNREACH: EvaluatePingResponse:=Destination Host Unreachable;
  ICMP_STATUS_DESTINATION_PROTOCOL_UNREACH: EvaluatePingResponse:=Destination Protocol Unreachable;
  ICMP_STATUS_DESTINATION_PORT_UNREACH: EvaluatePingResponse:=Destination Port Unreachable;
  ICMP_STATUS_NO_RESOURCE: EvaluatePingResponse:=No Resources;
  ICMP_STATUS_BAD_OPTION: EvaluatePingResponse:=Bad Option;
  ICMP_STATUS_HARDWARE_ERROR: EvaluatePingResponse:=Hardware Error;
  ICMP_STATUS_LARGE_PACKET: EvaluatePingResponse:=Packet Too Big;
  ICMP_STATUS_REQUEST_TIMED_OUT: EvaluatePingResponse:=Request Timed Out;
  ICMP_STATUS_BAD_REQUEST: EvaluatePingResponse:=Bad Request;
  ICMP_STATUS_BAD_ROUTE: EvaluatePingResponse:=Bad Route;
  ICMP_STATUS_TTL_EXPIRED_TRANSIT: EvaluatePingResponse:=TimeToLive Expired Transit;
  ICMP_STATUS_TTL_EXPIRED_REASSEMBLY: EvaluatePingResponse:=TimeToLive Expired Reassembly;
  ICMP_STATUS_PARAMETER: EvaluatePingResponse:=Parameter Problem;
  ICMP_STATUS_SOURCE_QUENCH: EvaluatePingResponse:=Source Quench;
  ICMP_STATUS_OPTION_TOO_BIG: EvaluatePingResponse:=Option Too Big;
  ICMP_STATUS_BAD_DESTINATION: EvaluatePingResponse:=Bad Destination;
  ICMP_STATUS_NEGOTIATING_IPSEC: EvaluatePingResponse:=Negotiating IPSEC;
  ICMP_STATUS_GENERAL_FAILURE: EvaluatePingResponse:=General Failure;
else EvaluatePingResponse:=Unknown Response;
end;
end;

function IsIPHostUp(Address:string):Boolean;
var Reply:ICMP_ECHO_REPLY; TryCount:Integer; WSAD:WSADATA; Status:DWORD;
begin
LastError:=;
while (Length(Address)>0)and(Address[1] in [#32,\,/]) do Delete(Address,1,1);
if WSAStartup(WS_VERSION_REQD,WSAD) = ICMP_SUCCESS then
  begin
  TryCount:=0;
  repeat
    Status:=DoPing(Address,Reply);
    case Status of
    ICMP_SUCCESS: Result:=True;
{    ICMP_STATUS_REQUEST_TIMED_OUT,ICMP_STATUS_DESTINATION_HOST_UNREACH: Result:=False;}
    else begin LastError:=EvaluatePingResponse(Status); Result:=false; end;
    end;
    Inc(TryCount);
  until (Result)or(TryCount>=4);
  WSACleanup;
  end
else LastError:=Winsock error failure;
end;

end.

И структуру INI файла:

[MAIN]
TimerInterval=10
Threshold=50
[MODEM]
ModemName=192.168.1.1
ModemUser=admin
ModemPass=admin
ModemPrompt=#
[HOSTS]
Host0=212.19.149.53
Host1=212.19.149.54
Host2=www.ya.ru
Host3=www.mail.ru
Host4=www.google.ru
Host5=
Host6=
Host7=
Host8=
Host9=




Все бы ничего, однако иногда телнет глючит и говорит об ошибке подключения к модему (и в отладочном логе виден мусор, вместо приветствия). Даже и не знаю почему, но после нескольких попыток срабатывает. Видимо придется писать телнет клиент ручками....