98_WOL: Probleme mit Ping und UDP

Begonnen von vbs, 10 Januar 2015, 13:56:01

Vorheriges Thema - Nächstes Thema

Dr. Boris Neubert

Hallo,

wenn die Maschine NICHT erreichbar ist, dauert es bis zum Timeout.

Viele Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Dietmar63

Aha,

danke - bei mir ist das NAS immer erreichbar. Deshalb ärgere ich mich nicht darüber und habe auch nicht die Notwendigkeit gesehen es zu verbessern.

Sollte man die ganzen komplizierten Umsetzungen mit BlockingCall nicht auch auf diese viel einfachere Variante umbauen. Mit BlockingCall habe ich mich auch mal abgequält.
Gruß Dietmar
FB7390, CUL, 2 FHT, FS20
modules: 98_WOL.pm, 98_Heating_Control.pm,   98_WeekdayTimer.pm, 98_RandomTimer.pm, 59_Twilight.pm

vbs

Könntest du den Code mal bitte zeigen, wie das jetzt aussieht? Du musst ja der Gegenstelle weiterhin eine gewisse Antwortzeit einräumen (üblicherweise 1 Sekunde). Also ohne fork kann ich mir gar nicht vorstellen, wie man das mit einem einzigen Funktionsaufruf non-blocking implementieren könnte. Um einen "richtigen" Ping handelt es sich dabei ohnehin nicht mehr, so wie ich das verstehe.

Meine bescheidene Meinung: Mit dem PRESENCE-Modul existiert Code, der einen echten ICMP-Ping non-blocking ausführt und genau dafür gemacht wurde. Ein Teil des Codes in WOL reimplementiert damit ja Teile des PRESENCE-Moduls. Ich persönlich würde die ganzen Ping-Sachen aus WOL rausnehmen, ehrlich gesagt. Wer Ping- bzw. Presence-Funktionalität benötigt, der möge das PRESENCE-Modul nehmen und wer Wake-On-LAN braucht, der soll das WOL-Modul nehmen. Ist aber vermutlich eine eher kontroverse Position meinerseits :)

Dietmar63

Ich bin noch in der Experimentierphase(padre).

a) man pingt den host mit  $p->ping($hostname, $timeout); an.
b) setzt eines Timers mit einer neuen Auswertfunktion nach (timeout+1) Sekunden.
c) in der Auswertfunktion werden die ACKs und nACKs ausgewertet und die Readings versorgt:
# ACK 
  while (($host,$rtt,$ip) = $p->ack() ) {
     print "HOST: $host [$ip] ACKed in $rtt seconds.\n";
  }
 
  foreach $hostname (@hosts) {
    my $nack = $p->nack($hostname);
    if ($nack) {
       print "msg $hostname $nack\n";
    }
  }


@Boris
wäre das so richtig?
Gruß Dietmar
FB7390, CUL, 2 FHT, FS20
modules: 98_WOL.pm, 98_Heating_Control.pm,   98_WeekdayTimer.pm, 98_RandomTimer.pm, 59_Twilight.pm

Dr. Boris Neubert

Zitat von: Dietmar63 am 11 Januar 2015, 13:51:16
wäre das so richtig?

So würde man das in FHEM typischerweise(R) tun.

Ich habe gerade nachgesehen, ob Net::Ping Callbacks unterstützt, tut es aber nicht. Schade.

Kürzlich wurde AnyEvent im Developer-Board vorgestellt. Schien mir sehr vielversprechend. Man schreibt damit sehr sauberen Code. Vielleicht eine Option?

Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Dietmar63

Callbacks braucht man nicht.
man kann es so machen:


################################################################################
sub WOL_UpdateReadings($) {
  my ($hash) = @_;

  my $timeout = 2;
  my $ping    = Net::Ping->new("syn",1);
 
  $ping->hires();
 
  $ping->ping($hash->{IP}, $timeout);
  $hash->{ping} = $ping;
 
  InternalTimer(gettimeofday()+$timeout, "WOL_UpdateReadingsCallback", $hash, 0);
}
################################################################################
sub WOL_UpdateReadingsCallback() {
  my ($hash) = @_;
 
  my $name  = $hash->{NAME};
 
  my $ping = $hash->{ping};

  readingsBeginUpdate ($hash);
 
  if (my ($host,$rtt,$ip) = $ping->ack($hash->{IP})) {
    Log3 $hash, 3, "HOST: $host [$ip] xACKed in $rtt seconds";
    Log3 $hash, 5, "[$name] ping succesful - state = on";
    readingsBulkUpdate   ($hash, "isRunning", "true");
    readingsBulkUpdate   ($hash, "state",     "on");
  } else {
    Log3 $hash, 5, "[$name] ping not succesful - state = on";
    readingsBulkUpdate   ($hash, "isRunning", "false");
    readingsBulkUpdate   ($hash, "state",     "off");
  }
 
  $ping->close(); delete $hash->{ping};
 
  readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
  WOL_SetNextTimer($hash);
}


Leider funktioniert genau das auf der FB nicht:

in Zeile:
  my $p= Net::Ping->new("syn",1);
kommt die Fehlermeldung:
Can't get tcp echo port by name at ./FHEM/98_WOL.pm line 130

  my $p= Net::Ping->new("syn");
  my $p= Net::Ping->new();

funktionieren auch nicht.
Gruß Dietmar
FB7390, CUL, 2 FHT, FS20
modules: 98_WOL.pm, 98_Heating_Control.pm,   98_WeekdayTimer.pm, 98_RandomTimer.pm, 59_Twilight.pm

Dr. Boris Neubert

Zitat von: Dietmar63 am 11 Januar 2015, 15:16:24
Leider funktioniert genau das auf der FB nicht:

in Zeile:
  my $p= Net::Ping->new("syn",1);
kommt die Fehlermeldung:
Can't get tcp echo port by name at ./FHEM/98_WOL.pm line 130

  my $p= Net::Ping->new("syn");
  my $p= Net::Ping->new();

funktionieren auch nicht.

Fritten sind in Bezug auf FHEM sterbende Systeme. Willst Du das wirklich unterstützen?

Das Problem sitzt in der Fritte, vermutlich ist der Port in /etc/services nicht definiert und dann schlägt getservbyname() fehl.

Mit etwas Arbeit kannst Du vielleicht eine Klasse von Net::Ping ableiten, die getservbyname() durch etwas hartkodiertes ersetzt.

Viele Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Dietmar63

ZitatFritten sind in Bezug auf FHEM sterbende Systeme. Willst Du das wirklich unterstützen?
...
Mit etwas Arbeit kannst Du vielleicht eine Klasse von Net::Ping ableiten, die getservbyname() durch etwas hartkodiertes er

Das scheint mir sehr viel Neuland zu werden. Dazu habe ich keine Zeit und außerdem sollte es dann einfacher sein BlockingCall() aufzurufen, zumal es dazu viel Doku gibt.
Gruß Dietmar
FB7390, CUL, 2 FHT, FS20
modules: 98_WOL.pm, 98_Heating_Control.pm,   98_WeekdayTimer.pm, 98_RandomTimer.pm, 59_Twilight.pm

Dietmar63

Ich habe mich entschieden mal schnell BlockingCall() in WOL einzubauen.
Kann das mal jemand reviewen. Es scheint bei mir zu funktionieren.


################################################################################
sub WOL_Undef($$) {

  my ($hash, $arg) = @_;

  RemoveInternalTimer($hash);
  BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
  return undef;
}
################################################################################
################################################################################
################################################################################
sub WOL_UpdateReadingsX($) {
   my ($hash) = @_;
   
   my $blockingFn = "WOL_Ping";
   my $arg        = $hash->{NAME}."|".$hash->{IP};
   my $finishFn   = "WOL_PingDone";
   my $timeout    = 3;
   my $abortFn    = "WOL_PingAbort";
   
   $hash->{helper}{RUNNING_PID} =
      BlockingCall($blockingFn, $arg, $finishFn, $timeout, $abortFn, $hash)
         unless(exists($hash->{helper}{RUNNING_PID}));;
         
}
################################################################################
sub WOL_Ping($){
   my ($string) = @_;
   my ($name, $ip) = split("\\|", $string);
   my $hash = $defs{$name};
   
   my $ping = "ping -c 1 -w 2 $ip";
   my $res = qx ($ping);
      $res = ""   if (!defined($res));
 
   Log3 $hash, 5, "[$name] executing: $ping";
 
   my $erreichbar = !($res =~ m/100%/);
   my $return = "$name|$erreichbar";
   return $return;
}
################################################################################
sub WOL_PingDone($){
   my ($string) = @_;
   my ($name, $erreichbar) = split("\\|", $string);
   my $hash = $defs{$name};
   
   readingsBeginUpdate ($hash);

   if ($erreichbar) {
      Log3 $hash, 5, "[$name] ping succesful - state = on";
      readingsBulkUpdate   ($hash, "isRunning", "true");
      readingsBulkUpdate   ($hash, "state",     "on");
   } else {
      Log3 $hash, 5, "[$name] ping not succesful - state = on";
      readingsBulkUpdate   ($hash, "isRunning", "false");
      readingsBulkUpdate   ($hash, "state",     "off");
   }
 
   readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
   
   delete($hash->{helper}{RUNNING_PID});
   WOL_SetNextTimer($hash);
}
################################################################################
sub WOL_PingAbort($){
  my ($hash) = @_;

  delete($hash->{helper}{RUNNING_PID});

  Log3 $hash->{NAME}, 3, "BlockingCall for ".$hash->{NAME}." was aborted";
  WOL_SetNextTimer($hash);
}
Gruß Dietmar
FB7390, CUL, 2 FHT, FS20
modules: 98_WOL.pm, 98_Heating_Control.pm,   98_WeekdayTimer.pm, 98_RandomTimer.pm, 59_Twilight.pm

Dietmar63

@vbs:

BlockingCall() scheint bei mir für den Ping zu funktionieren.

Es gibt aber ein Problem mit der neuen Funktion useUdpBroadcast. Ich kann nicht sagen, dass es falsch läuft, aber bei mir funktioniert der WOL nicht mit der Broardcast-Adresse 255.255.255.255.

Ich konnte mich noch daran erinnern, dass ich es einmal vor langer Zeit mit 192.168.2.255 geschafft habe - so etwas wie die kleine Broardcast-Adresse.
Ich schlage vor, dass wir das Attribut dahingehend verändern sollten, dass man die Broardcast-Adresse  an sich vorgeben kann. Dann haben wir größtmögliche Flexibilität:

attr NAS useUdpBroadcast 255.255.255.255
attr NAS useUdpBroadcast 192.168.2.255


Was hältst du davon? Kannst du dir das Verhalten bei mir erklären?
Gruß Dietmar
FB7390, CUL, 2 FHT, FS20
modules: 98_WOL.pm, 98_Heating_Control.pm,   98_WeekdayTimer.pm, 98_RandomTimer.pm, 59_Twilight.pm

vbs

Also gut erklären kann ich es nicht. Aber nach nochmaliger Googelei folgendes herausgefunden:
255.255.255.255 ist ein Broadcast der implizit das eigene Netz meint. Also im Endeffekt auch 192.168.2.255. Hab aber wieder keine Ahnung, welches das "eigene Netz" sein soll, wenn man mehrere IPs hat. Entweder spielt da auch das OS rein, bei der Entscheidung wie es rausgeschickt wird, oder es liegt sogar am Endgerät, ob dann letztendlich auf das WOL-Paket reagiert wird, oder nicht.

Wie auch immer:
Genau erklären kann ich es nicht, aber ich finde die Idee sehr gut, die ganze Adresse per Attribut konfigurierbar zu machen.

Jedoch halte ich mehr und mehr das Schicken an die tatsächliche Ziel-Adresse (zB 192.168.0.27) für nicht gut. Ich denke, da sind Probleme vorprogrammiert (wegen dem genannten ARP-Problem). Alle Stellen, die ich jetzt nochmal gelesen habe bzgl. WOL reden auch immer nur von Broadcast-Adressen (also 192.168.0.255 oder auch 255.255.255.255). Ist die Frage, was man stattdessen macht. Eventuell 255.255.255.255 als default und ansonsten muss es der User konfigurieren?

(Auch interessant: http://search.cpan.org/~tequeter/Net-Route-v0.02/lib/Net/Route/Table.pm)

Dietmar63

ZitatJedoch halte ich mehr und mehr das Schicken an die tatsächliche Ziel-Adresse (zB 192.168.0.27) für nicht gut. Ich denke, da sind Probleme vorprogrammiert (wegen dem genannten ARP-Problem). Alle Stellen, die ich jetzt nochmal gelesen habe bzgl. WOL reden auch immer nur von Broadcast-Adressen (also 192.168.0.255 oder auch 255.255.255.255). Ist die Frage, was man stattdessen macht. Eventuell 255.255.255.255 als default und ansonsten muss es der User konfigurieren?

dann würde ich 192.168.0.255 als Standard vorschlagen, weil ich irgendwo gelesen hatte, dass dies die Broadcast-Adressen  des eigenen lokalen Netzes(class C) ist.

Genau müsste es so sein(vermute ich):
IP  bitweisesOR ( bitweisesNOT subnetzmask) sein.
192.168.0.27 bitweisesOR ( bitweisesNOT 255.255.255.0) --->>> 192.168.0.255.

Probier mal, ob bei dir folgende IP  funktioniert: also 192.168.0.255
Je nach Größe des Netzes ist die Subnetzmask unterschiedlich 255.255.255.0 255.255.0.0 oder 255.0.0.0

255.255.255.255  ist mir zu gefährlich, a) weil es bei mir schon nicht funktioniert und b) ich dann viele Tickets erwarte.
Gruß Dietmar
FB7390, CUL, 2 FHT, FS20
modules: 98_WOL.pm, 98_Heating_Control.pm,   98_WeekdayTimer.pm, 98_RandomTimer.pm, 59_Twilight.pm

vbs

Also bei 192.168.0.255 setzt das ja voraus, dass die Leute als Netz 192.168.0.x nutzen. Das passt auf mich schonmal nicht und ich kenne auch einige andere Leute die 192.168.1.2 oder auch 192.168.2.x nutzen. Das wäre dann schon eine recht spezieller Default...
Ich hab keine Ahnung bei wievielen Leuten 255.255.255.255 funtkionieren würde, aber es wäre immerhin generisch. Plan B wäre sonst echt nur das Auslesen der Routing-Tabelle fürchte ich :( Hab gerade keine gute Idee...

Dietmar63

so müßste man es machen:

Das ist eine Formel(Varialblen in Rot):
IP  bitweisesOR ( bitweisesNOT subnetzmask)

192.168.0.27 bitweisesOR ( bitweisesNOT 255.255.255.0) --->>> 192.168.0.255.
192.168.1.27 bitweisesOR ( bitweisesNOT 255.255.255.0) --->>> 192.168.1.255.
192.168.2.27 bitweisesOR ( bitweisesNOT 255.255.255.0) --->>> 192.168.2.255.
Gruß Dietmar
FB7390, CUL, 2 FHT, FS20
modules: 98_WOL.pm, 98_Heating_Control.pm,   98_WeekdayTimer.pm, 98_RandomTimer.pm, 59_Twilight.pm

Dietmar63

ZitatDie meisten Router erzeugen einen Ethernet-Broadcast, wenn sie ein Paket an die IP-Broadcast-Adresse weiterleiten sollen. Dies ist immer die höchste Adresse im lokalen Subnetz und hängt daher von der Netzmaske ab. In einem typischen Netz mit der Netzmaske 255.255.255.0 wäre dies zum Beispiel die 192.168.1.255. Der IP-Stack des Routers setzt diesen IP-Broadcast dann in einen Ethernet-Broadcast um, und das Paket erreicht alle PCs im LAN. Eine Umleitung eines UDP-Ports des Routers auf die interne Broadcast-Adresse macht das ankommende UDP-Paket zu einem Ethernet-Frame, den alle Rechner im LAN erhalten.

http://www.heise.de/netze/artikel/Port-Forwarding-224180.html
Gruß Dietmar
FB7390, CUL, 2 FHT, FS20
modules: 98_WOL.pm, 98_Heating_Control.pm,   98_WeekdayTimer.pm, 98_RandomTimer.pm, 59_Twilight.pm