UDP Datagramme empfangen

Begonnen von Sailor, 23 Januar 2019, 22:33:15

Vorheriges Thema - Nächstes Thema

herrmannj


Sailor

Hallo Hermann
Zitat von: herrmannj am 26 Januar 2019, 21:46:10
klar:)

Mein letzter Post hat den richtigen Auszug von wireshark von genau dem Gerät, was ich in dem Modul versuche abzuhören.

Für mich gibt es nur zwei Möglichkeiten
a) entweder lese ich mich jetzt ganz langwierig in das Thema UDP bzw Multicast datagramme ein
oder
b) ich hoffe auf einen Experten in dieser Runde, der mir die entsprechenden Code Zeilen korrigiert.

Wie gesagt, ich habe von diesem Thema 0 Schimmer.

Danke dir!

Gruss
   Sailor
******************************
Man wird immer besser...

CoolTux

Zitat von: Sailor am 26 Januar 2019, 21:02:50
So,

habe mal das Datagram von einem Besitzer bekommen:

Internet Protocol Version 4, Src: 192.168.xx.xx, Dst: 255.255.255.255
User Datagram Protocol, Src Port: 3074, Dst Port: 35344


bzw.


Internet Protocol Version 4, Src: 192.168.xx.xx, Dst: 255.255.255.255
User Datagram Protocol, Src Port: 3074, Dst Port: 6524


Könnt Ihr als Experten damit was anfangen?

Gruss
    Sailor

Sieht ganz anders aus.
192.168. ist die IP Deines DoorBird? Und der Port ist auch immer der selbe. Kann man da nicht einfach eine UDP Clientverbindung zu dem Teil auf machen?


my $socket = new IO::Socket::INET   (   PeerHost => $host,
                                            PeerPort => $port,
                                            Proto => 'udp',
                                            Timeout => $timeout
                                        )
        or return Log3 $name, 4, " ($name) Couldn't connect to $host:$port";      # open Socket
       
    $hash->{FD}    = $socket->fileno();
    $hash->{CD}    = $socket;         # sysread / close won't work on fileno
    $selectlist{$name} = $hash;
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

Sailor

Hallo CoolTux

Zitat von: CoolTux am 28 Januar 2019, 08:04:17
Sieht ganz anders aus.
192.168. ist die IP Deines DoorBird? Und der Port ist auch immer der selbe. Kann man da nicht einfach eine UDP Clientverbindung zu dem Teil auf machen?

Can't call method "fileno" on an undefined value at ./FHEM/73_DoorBird.pm line 176.

OK, werde ich versuchen, aber wie vermeide ich bei einer Neu-Definition des Device nach einem Neustart (das funktioniert wohl noch), dass mein fhem - System mit der Fehlermeldung oben abschmiert?
Der Fehler ist auf anderen Systemen reproduzierbar...

Gruss
    Sailor
******************************
Man wird immer besser...

CoolTux

Genau so wie ich es geschrieben habe.

or return Log3 $name, 4, " ($name) Couldn't connect to $host:$port";

Wenn Du nur schreibst
my $conn = IO::Socket::INET->new(Proto=>"udp",LocalPort=>3702);
Aber nicht prüfst ob das erstellen des Objektes auch wirklich geklappt hat dann wird das nichts.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

herrmannj

ich vermute mal das reuse port fehlt, kann das aber nur raten.

Ganz um das einlesen wirst Du nicht herumkommen, wie willst Du sonst bugs in Deinem code finden wenn Du nicht verstehst was er tut? (Genau das ist was gerade passiert... Glaub ich..)

Sowohl Andre als auch ich haben funktionierenden code zum abtippen in die Runde geworfen. Aber minimale Abweichungen davon können zu Fehlern, vmtl trivialen, führen - das ist aber auch normal.

Stell doch Deinen code mal komplett ein. Ich kann Dir den udp Teil sonst schon schreiben, aber was hilft Dir das dann?

Sailor

Moin zusammen

Zitat von: herrmannj am 28 Januar 2019, 11:39:55
ich vermute mal das reuse port fehlt, kann das aber nur raten.

Der folgende Code wird in der DoorBird_Define() aufgerufen bzw in der DoorBird_Init() definiert / verwiesen:

sub DoorBird_Initialize($)
{
...
    $hash->{ReadFn}          = "DoorBird_Read";
...
}

sub DoorBird_OpenSocketConn($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $conn;


### Check if json can be parsed into hash
eval
{
$conn = new IO::Socket::INET (
PeerAddr  => '255.255.255.255',
PeerPort  =>  6524
Proto     => 'udp',
Broadcast => 1
);
1;
}
or do
{
### Log Entry for debugging purposes
Log3 $name, 3, $name. " : DoorBird_OpenSocketConn - Socket Connection cannot be established";

return
};

### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_OpenSocketConn - Socket Connection has been established";
Log3 $name, 5, $name. " : DoorBird_OpenSocketConn - SocketConnection        : " . $conn;

$hash->{FD}    = $conn->fileno();
$hash->{CD} = $conn;
$selectlist{$name} = $hash;

return
}

sub DoorBird_Read($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $buf;
my $data;

$hash->{CD}->recv($buf, 16);
$data = unpack('H*', $buf);

### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Read - UDP Client said                   : " . $data;

Dispatch($hash, $buf);
}


führt zwar zu einem Anlegen einer Verbindung

DoorBird_OpenSocketConn - Socket Connection has been established
DoorBird_OpenSocketConn - SocketConnection        : IO::Socket::INET=GLOB(0x725d0d0)


aber das DoorBird_Read kommt dennoch nicht zum Zuge, sobald im LAN folgende Messages auftauchen:

Internet Protocol Version 4, Src: 192.168.xx.xx, Dst: 255.255.255.255
User Datagram Protocol, Src Port: 3074, Dst Port: 6524


Ich habe mich jetzt ein wenig in Broadcast, Unicast und Multicast eingelesen und habe mir von den jeweiligen Testern und Besitzern bestätigen lassen, dass der DoorBird ohne irgendwelche weiteren Router/Firewall am gleichen Switch hängen.

Eigentlich müsste doch was kommen...

Die von Dir und André in die Runde geworfenen Code-Snippets zielen, sofern ich das richtig verstanden habe, auf Unicast bzw. Multicast ab und ist wohl nicht mit dem o.g. Broadcast kompatibel.

Habt Ihr da noch eine andere Idee?

Danke

Gruß
    Sailor
******************************
Man wird immer besser...

herrmannj

Moin Sailor,

Wenn Du den socket via IO::Socket::INET (https://perldoc.perl.org/IO/Socket/INET.html) erstellen möchtest:

PeerAddr, PeerPort, Broadcast  sind dafür nicht erforderlich.

Stattdessen musst Du LocalPort auf den Port setzen welcher empfängt (6524), "UDP" bleibt natürlich.

Reuse port kann vmtl in diesem Szenario entfallen. Ich würde den usern empfehlen den FHEM Server komplett neu zu starten wenn Du das angepasst hast bevor sie testen.

Sailor

Hallo Herrmann

Zitat von: herrmannj am 01 Februar 2019, 14:19:43
Wenn Du den socket via IO::Socket::INET (https://perldoc.perl.org/IO/Socket/INET.html) erstellen möchtest:
PeerAddr, PeerPort, Broadcast  sind dafür nicht erforderlich.
Stattdessen musst Du LocalPort auf den Port setzen welcher empfängt (6524), "UDP" bleibt natürlich.
Reuse port kann vmtl in diesem Szenario entfallen. Ich würde den usern empfehlen den FHEM Server komplett neu zu starten wenn Du das angepasst hast bevor sie testen.

Mit dem Code


$conn = new IO::Socket::INET (
Listen    => 5,
LocalAddr => 'localhost',
LocalPort => 6524,
Proto     => 'udp'
);


sowie


$conn = new IO::Socket::INET (
Listen    => 5,
LocalAddr => '192.168.178.vomfhemServer',
LocalPort => 6524,
Proto     => 'udp'
);


bzw.


$conn = new IO::Socket::INET (
LocalPort => 6524,
Proto     => 'udp'
);


lassen sich keine Socket - Verbindungen aufbauen.

Das Beispiel

$conn = new IO::Socket::INET (
PeerAddr => 'www.perl.org',
PeerPort => 'http(80)',
Proto    => 'tcp'
);

lässt sich aufbauen und es kommt über DoorBird_Read rein:

Unknown code , help me!
DoorBird_Read - UDP Client said buf               :
DoorBird_Read - UDP Client said data              :
dispatch


Es ist zum Mäusemelken...

Gruss
    Sailor
******************************
Man wird immer besser...

herrmannj

#24
Was heist denn "lassen sich keine Socket - Verbindungen aufbauen." ?

UDP ist ein verbindungsloses Protokoll.

Ein Beispiel:
package main;

use strict;
use warnings;
use utf8;

use IO::Socket::INET;
use Data::Dumper;

my $conn = new IO::Socket::INET (
LocalPort => 6524,
Proto     => 'udp'
) or die("failed...");

print Dumper $conn;

1;

Ausgabe:
$VAR1 = bless( \*Symbol::GEN0, 'IO::Socket::INET' );
Funktioniert.


Nachtrag: ergänzt, ein receive
package main;

use strict;
use warnings;
use utf8;

use IO::Socket::INET;
use Data::Dumper;

my $conn = new IO::Socket::INET (
LocalPort => 6524,
Proto     => 'udp'
) or die("failed...");

print Dumper $conn;

my ($data,$flags);
$conn->recv($data, 1024, $flags);
print "Received datagram from ", $conn->peerhost,", flags ", $flags || "none", ": $data\n";

1;


justme1968

ich weiss nicht ob dein code oben noch aktuell ist, aber da fehlt ein , hinter 6524 deshalb geht das eval schief.

übrigens: du brauchst du kein eval. einfach $conn auswerten reicht.

wenn du PeerAddr und PeerPort verwendest baust du eine verbindung zu einem ziel auf das auf eine verbindung wartet.

wenn du beides weg lässt wartest du das dir jemand daten schickt.

wenn du auf reagieren willst wenn dir jemand was sendet braucht du letzteres und du kannst beide fälle nicht vergleichen.

hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Sailor

Zitat von: herrmannj am 01 Februar 2019, 21:23:39
Was heist denn "lassen sich keine Socket - Verbindungen aufbauen." ?

UDP ist ein verbindungsloses Protokoll.

Ein Beispiel:
package main;

use strict;
use warnings;
use utf8;

use IO::Socket::INET;
use Data::Dumper;

my $conn = new IO::Socket::INET (
LocalPort => 6524,
Proto     => 'udp'
) or die("failed...");


Genau an dieser Stelle steht dann ein

failed... at ./FHEM/73_DoorBird.pm line 627.

im fhem-Log und fhem ist abgestürzt...
Daher hatte ich das im eval.

Nehmen wir mal an, ich würde im Wireshark laufend folgende Meldungen zum Testen nehmen wollen:


192.168.178.21 239.255.255.250 UDP 1265 3702 → 3702 Len=4183


Mir ist bewusst, dass die "239.255.255.250" keine Broadcast - Adresse im eigentlichen Sinne ist, aber das dürfte bei dem Code unten eigentlich keine Rolle spielen, da er ja scheinbar auf alles reagiert was als Protokol "udp" gekennzeichnet und auf Port 3702 liegt.

Oder irre ich mich da?


###START###### Open UDP socket connection #####################################################################START####
sub DoorBird_OpenSocketConn($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $conn;
my $port = $hash->{helper}{UdpPort};
my $url  = $hash->{helper}{URL};
   $url  =~ s/:.*//;

### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_OpenSocketConn - url                     : " . $url;
Log3 $name, 5, $name. " : DoorBird_OpenSocketConn - port                    : " . $port;

## Check if connection can be opened
eval
{
$conn = new IO::Socket::INET (
LocalPort => 3702,
Proto     => 'udp'
);
1;
}
or do
{
### Log Entry for debugging purposes
Log3 $name, 3, $name. " : DoorBird_OpenSocketConn - IO::Socket::INET Error  : " . $@;

return
};


Log3 $name, 5, $name. " : DoorBird_OpenSocketConn - SocketConnection        : " . Dumper($conn);


if (defined($conn)) {
$hash->{FD}    = $conn->fileno();
$hash->{CD} = $conn;
$selectlist{$name} = $hash;

### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_OpenSocketConn - Socket Connection has been established";
}
else {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_OpenSocketConn - Socket Connection has NOT been established";
}
return
}
####END####### Open UDP socket connection ######################################################################END#####

###START###### After return of UDP message ####################################################################START####
sub DoorBird_Read($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $buf;
my $flags;
my $data;

my $PeerHost = $hash->{CD}->peerhost;

$hash->{CD}->recv($buf, 1024, $flags);
$data = unpack('H*', $buf);

### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Read - UDP Client said PeerHost          : " . $PeerHost;
Log3 $name, 5, $name. " : DoorBird_Read - UDP Client said buf               : " . $buf;
Log3 $name, 5, $name. " : DoorBird_Read - UDP Client said flags             : " . $flags;
Log3 $name, 5, $name. " : DoorBird_Read - UDP Client said data              : " . $data;

Dispatch($hash, $buf);
}
####END####### After return of UDP message #####################################################################END#####


a) Einen Neustart per "sudo reboot" erzwungen,
b) das DoorBird Device neu definiert,
und folgendes im Log entdeckt:


DoorBird_OpenSocketConn - url                     : 192.168.178.21
DoorBird_OpenSocketConn - port                    : 3702
DoorBird_OpenSocketConn - SocketConnection        : $VAR1 = undef;

DoorBird_OpenSocketConn - Socket Connection has NOT been established




## Check if connection can be opened
$conn = eval { ...

kommt zum gleichen Ergebnis.

Zumindest kommt es nicht zum fhem Absturz...

Warum klappt das bei Herrmann seiner perl-Routine und nicht innerhalb von einem fhem - Modul.

Habe ich irgendwas am RasPi nicht richtig installiert (Debian Pakete, Perl libs, ethernet card) oder lässt fhem irgendetwas nicht zu?
Rätsel über Rätsel... :-[

Vielleicht ist dies ein guter Zeitpunkt die Basics abzuklopfen.

Gruss
    Sailor
******************************
Man wird immer besser...

justme1968

du darfst niemals die verwenden. damit beendest du dein programm.

einfach if( $conn ) ...

ja du irrst dich. wenn du ein socken auf machst lauschst du nur auf bestimmten adressen. das ist ohne angabe von LocalAddr normalerweise nur localhost und alle ip adressen die deine interfaces haben. da sind ohne das du dafür sorgst keine multicast adressen dabei. 239.255.255.250 ist eine multicast adresse.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

herrmannj

Sailor,

nimm doch das script das ich oben gepostet habe und lass es einfach mal ohne fhem laufen. Dann kannst Du Dich Stück für Stück rantasten. Das "die" hat natürlich nichts in einem fhem Modul zu suchen.

Du postest immer im Wechsel Broadcast und Multicast Adressen. Was ist es denn nun ?  ;)

Noch als Idee: kann es sein dass der Port 6524 bei Dir schon geöffnet ist ?



Sailor

Hi justme
Zitat von: justme1968 am 01 Februar 2019, 22:44:01
ja du irrst dich. wenn du ein socken auf machst lauschst du nur auf bestimmten adressen. das ist ohne angabe von LocalAddr normalerweise nur localhost und alle ip adressen die deine interfaces haben. da sind ohne das du dafür sorgst keine multicast adressen dabei. 239.255.255.250 ist eine multicast adresse.

Ok, war ein Versuch Wert, dann bleibt nur der Versuch ein Broadcast zu senden.
Zum Beispiel vom RasPi mittels socat - udp-sendto:255.255.255.255:6524,broadcast.
Zumindest taucht das im tshark als 192.168.178.RasPi → 255.255.255.255 UDP 43 45181 → 6524 Len=1 auf

Auch ohne "die" und ohne "eval" bleibt das Problem, dass die Socket-Verbindung $conn undefiniert bleibt.


DoorBird_OpenSocketConn - SocketConnection        : $VAR1 = undef;
******************************
Man wird immer besser...