Dakuan
Anmeldungsdatum: 2. November 2004
Beiträge: 6489
Wohnort: Hamburg
|
Ich habe diesen post mal zum Anlass genommen, mich etwas mit Netzwerkprogrammierung zu befassen. Ausgegangen bin ich von dem Script, welches Marant-- dort verlinkt hat und von einem TCP Server/Client Beispiel aus dem Buch "Linux-UNIX-Programmierung". Herausgekommen ist da folgendes Programmfragment.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 | /*
** DLNA Test, Stufe 1
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF 1024
const char * query_message =
"M-SEARCH * HTTP/1.1\r\n"
"Host: 239.255.255.250:1900\r\n"
"Man: \"ssdp:discover\"\r\n"
"ST: urn:schemas-upnp-org:device:MediaServer:1\r\n"
"MX: 3.\r\n"
"User-Agent: gupnp-av-cp GSSDP/0.12.1\r\n";
int
send_query( void ) {
int udp_socket; // Socket-Descriptor
char * rcv_buf = malloc( BUF );
struct sockaddr_in address;
int size;
int cnt = 0;
//printf( "\e[2J" );
if( (udp_socket = socket( AF_INET, SOCK_DGRAM, 0 )) > 0 ) {
printf( "Socket wurde angelegt\n" );
memset( &address, 0, sizeof( address ) );
address.sin_family = AF_INET;
address.sin_port = htons( 1900 );
//address.sin_addr.s_addr = INADDR_ANY; // nur Server
inet_aton( "239.255.255.250", &address.sin_addr );
if( connect( udp_socket, (struct sockaddr*)&address, sizeof( address ) ) == 0 ) {
bind( udp_socket, (struct sockaddr*)&address, sizeof( address ) );
if( send( udp_socket, query_message, strlen( query_message ), 0 ) > 0 ) {
//printf( "Send query ok\n" );
do {
//printf( "----\n" );
size = recv( udp_socket, rcv_buf, BUF-1, 0 );
if( size > 0 ) {
rcv_buf[size] = '\0';
printf( "%s\n", rcv_buf );
printf( "\n" );
cnt++;
}
} while ( size > 0 );
}
}
}
close( udp_socket );
return cnt;
}
int
main( int argc, char **argv ) {
printf( " %d\n", send_query() );
return( EXIT_SUCCESS );
}
|
Leider zeigt das nichts an. Allerdings sagt mir TCPDUMP, dass es von einigen Geräten durchaus eine Reaktion gibt, die ich allerdings nicht darstellen kann. Das Programm scheint in der Funktion recv() festzuhängen. TCPDUMP zeigt:
@samurai:~$ sudo tcpdump -v -i enp3s0 udp
tcpdump: listening on enp3s0, link-type EN10MB (Ethernet), capture size 262144 bytes
18:35:14.454532 IP (tos 0x0, ttl 1, id 22355, offset 0, flags [DF], proto UDP (17), length 192)
samurai.fritz.box.46258 > 239.255.255.250.1900: UDP, length 164
18:35:14.455819 IP (tos 0x0, ttl 64, id 22387, offset 0, flags [DF], proto UDP (17), length 74)
samurai.fritz.box.59819 > 192.168.123.2.domain: 53162+ PTR? 250.255.255.239.in-addr.arpa. (46)
18:35:14.456457 IP (tos 0x0, ttl 64, id 33630, offset 0, flags [DF], proto UDP (17), length 448)
lager1.lan.1900 > samurai.fritz.box.46258: UDP, length 420
18:35:14.456491 IP (tos 0x0, ttl 1, id 53716, offset 0, flags [DF], proto UDP (17), length 384)
lager1.lan.43765 > 239.255.255.250.1900: UDP, length 356
18:35:14.456494 IP (tos 0x0, ttl 1, id 53717, offset 0, flags [DF], proto UDP (17), length 375)
lager1.lan.43765 > 239.255.255.250.1900: UDP, length 347
18:35:14.456496 IP (tos 0x0, ttl 1, id 53718, offset 0, flags [DF], proto UDP (17), length 427)
lager1.lan.43765 > 239.255.255.250.1900: UDP, length 399
18:35:14.456514 IP (tos 0x0, ttl 1, id 53719, offset 0, flags [DF], proto UDP (17), length 439)
lager1.lan.43765 > 239.255.255.250.1900: UDP, length 411
18:35:14.484912 IP (tos 0x0, ttl 64, id 37337, offset 0, flags [DF], proto UDP (17), length 72)
samurai.fritz.box.33223 > 192.168.123.2.domain: 22814+ PTR? 2.123.168.192.in-addr.arpa. (44)
18:35:14.487912 IP (tos 0x0, ttl 64, id 52884, offset 0, flags [DF], proto UDP (17), length 73)
samurai.fritz.box.53342 > 192.168.123.2.domain: 46639+ PTR? 62.123.168.192.in-addr.arpa. (45)
18:35:20.641810 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 55)
SBTouch.fritz.box.17784 > 255.255.255.255.17784: UDP, length 27
18:35:20.643353 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 65)
SBTouch.fritz.box.38464 > 255.255.255.255.3483: UDP, length 37
18:35:20.643666 IP (tos 0x0, ttl 64, id 12142, offset 0, flags [DF], proto UDP (17), length 73)
samurai.fritz.box.58472 > 192.168.123.2.domain: 4358+ PTR? 38.123.168.192.in-addr.arpa. (45)
18:35:20.645777 IP (tos 0x0, ttl 64, id 49393, offset 0, flags [DF], proto UDP (17), length 173)
192.168.123.2.domain > samurai.fritz.box.58472: 4358* 2/1/1 38.123.168.192.in-addr.arpa. PTR SBTouch.fritz.box., 38.123.168.192.in-addr.arpa. PTR SqueezeboxTouch.fritz.box. (145)
^C
13 packets captured
21 packets received by filter
8 packets dropped by kernel
@samurai:~$ Erwarten würde ich in etwa so etwas:
@samurai:~/prog/scripte/dlna$ ./bc1.sh
sending:
M-SEARCH * HTTP/1.1
Host: 239.255.255.250:1900
Man: "ssdp:discover"
ST: urn:schemas-upnp-org:device:MediaServer:1
MX: 3.
User-Agent: gupnp-av-cp GSSDP/0.12.1
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1810
DATE: Sun, 10 Jul 2022 16:43:28 GMT
ST: urn:schemas-upnp-org:device:MediaServer:1
USN: uuid:4d696e69-444c-164e-9d41-245ebe1ffe86::urn:schemas-upnp-org:device:MediaServer:1
EXT:
SERVER: 3.4.6-generic Microsoft-Windows/6.1 Windows-Media-Player-DMS/12.0.7601.17514 DLNADOC/1.50 UPnP/1.0 QNAPDLNA/1.0
LOCATION: http://192.168.123.62:8200/rootDesc.xml
Content-Length: 0
HTTP/1.1 200 OK
LOCATION: http://192.168.123.1:49000/MediaServerDevDesc.xml
SERVER: box UPnP/1.0 AVM FRITZ!Box 7490 113.07.29
CACHE-CONTROL: max-age=1800
EXT:
ST: urn:schemas-upnp-org:device:MediaServer:1
USN: uuid:fa095ecc-e13e-40e7-8e6c-3481c40a10c5::urn:schemas-upnp-org:device:MediaServer:1
$
Diese Anzeige ist das Ergebnis eines Scripts, dass ich aus einem Unterprogramm des oben erwähnten Scrips gewonnen habe (und was noch nicht fehlerfrei ist). Die Frage ist jetzt, was muss ich ändern, um die, wie auch immer gearteten, Reaktionen der anderen Geräte anzuzeigen? Welcher Denkfehler ist mir da unterlaufen?
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6489
Wohnort: Hamburg
|
Nachdem ich ein etwas umfangreicheres Buch konsultiert habe, bin ich einen kleinen Schritt weiter. bind() hatte ich gestern schon raus genommen und jetzt auch noch connect(). Zusätzlich habe ich send() und recv() gegen sendto() und recvfrom() getauscht. Jetzt sehe ich schon mal etwas.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13177
|
Dakuan schrieb:
bind() hatte ich gestern schon raus genommen und jetzt auch noch connect(). Zusätzlich habe ich send() und recv() gegen sendto() und recvfrom() getauscht. Jetzt sehe ich schon mal etwas.
Ja, connect ist da Fehl am Platz, weil UDP ja gerade verbindungslos ist. Was mir sonst noch auffällt: die Schleife von 44 bis 53 kannst Du auch so wie in 33 machen - das spart eine redundante Prüfung | while ( ( size = recv( udp_socket, rcv_buf, BUF-1, 0 ) ) > 0 ) {
//printf( "----\n" );
rcv_buf[size] = '\0';
printf( "%s\n", rcv_buf );
printf( "\n" );
cnt++;
}
|
Zeile 35 finde ich etwas seltsam: ich würde die Felder der Struktur lieber direkt füllen anstatt die ganze Struktur zu nullen. Dann sieht man, welche Werte verwendet werden. Bin aber auch kein C-Programmierer. 😉
|
ChickenLipsRfun2eat
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Dakuan schrieb: bind() hatte ich gestern schon raus genommen und jetzt auch noch connect(). Zusätzlich habe ich send() und recv() gegen sendto() und recvfrom() getauscht. Jetzt sehe ich schon mal etwas.
Das scheint der richtige Schritt zu sein. Hab leider in meinen Snippets nix mit UDP drin, nur TCP. Möchtest du da sowas wie curl nachbauen? Oder welches Ziel hast du? Für XML-Parsing mit expat brauchste gute Nerven 😉 Da würde ich eher zu Python, Perl & Co greifen oder ein Framework wie Qt nutzen (C++). rklm schrieb: Zeile 35 finde ich etwas seltsam: ich würde die Felder der Struktur lieber direkt füllen anstatt die ganze Struktur zu nullen. Dann sieht man, welche Werte verwendet werden. Bin aber auch kein C-Programmierer. 😉
Das ist das klassische. Heute schreibt man das bei der Initialisierung als struct sockaddr_in address = { 0 }; . Und das muss sein, da C nicht automatisch mit 0 initialisiert und sonst Reste aus dem Speicher drinstehen können. // Nachtrag: Vor lauter Gelaber ganz vergessen: https://sourceforge.net/p/minidlna/git/ci/master/tree/minissdp.c ⇨ Da kannst du dir den Aufbau klauen.
|
ChickenLipsRfun2eat
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 | #include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
int main( void ) {
int sock,
bytes_recv;
socklen_t sin_size;
struct sockaddr_in server_addr;
struct hostent *host;
char send_data[1024],
recv_data[1024];
host = ( struct hostent * ) gethostbyname( ( char * ) "239.255.255.250" );
if( ( sock = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) {
perror("socket error");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons( 1900 );
server_addr.sin_addr = *( ( struct in_addr * ) host->h_addr );
bzero( &( server_addr.sin_zero ) ,8 );
sin_size = sizeof( struct sockaddr );
strcpy( send_data, "M-SEARCH * HTTP/1.1\r\n"
"Host: 239.255.255.250:1900\r\n"
"Man: \"ssdp:discover\"\r\n"
"ST: urn:schemas-upnp-org:device:MediaServer:1\r\n"
"MX: 3.\r\n"
"User-Agent: gupnp-av-cp GSSDP/0.12.1\r\n" );
sendto( sock, send_data, strlen(send_data), 0, (struct sockaddr *)&server_addr, sizeof( struct sockaddr ) );
bytes_recv = recvfrom( sock, recv_data, 1024, 0, ( struct sockaddr * ) &server_addr, &sin_size);
recv_data[bytes_recv]= '\0';
printf("Received :%s\n",recv_data);
}
|
Ausgabe: Received :HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1810
DATE: Mon, 11 Jul 2022 15:17:36 GMT
ST: urn:schemas-upnp-org:device:MediaServer:1
USN: uuid:4d696e69-444c-164e-9d41-f079593902f3::urn:schemas-upnp-org:device:MediaServer:1
EXT:
SERVER: 5.15.12-arch1-1 DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.3.1
LOCATION: http://192.168.2.50:8200/rootDesc.xml
Content-Length: 0 Komplettes Beispiel: http://matrixsust.blogspot.com/2011/10/udp-server-client-in-c.html (Google-Cookies!)
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6489
Wohnort: Hamburg
|
Ja, connect ist da Fehl am Platz, weil UDP ja gerade verbindungslos ist.
In diesem Fall sicherlich ja. Aber es ist auch nicht grundsätzlich verboten, wie ich heute Morgen gelesen hatte. Wenn man mehrere Pakete an ein Ziel seden will, könnte man dann auch write() nehmen. Das memset() habe ich tatsächlich nicht in allen Beispielen gefunden. Aber direkt füllen gehr nicht immer, da es sich, wenn ich das richtig behalten habe, um 3 leicht unterschiedliche Strukturen handelt (UNIX, IPv4, IPv6). In "The Linux Programming interface" ist das in allen Beispielen so. Und an der Schleife muss ich sowieso noch arbeiten. Die läuft endlos. Und eine Zeitüberwachung würde sicherlich auch nicht schaden.
... Hab leider in meinen Snippets nix mit UDP drin, nur TCP ...
Ja, das wird wohl gerne nur nebenbei erwähnt. Deshalb basierte der Code von gestern auf einem Beispiel, das ich "auf Verdacht" abgewandelt hatte.
Möchtest du da sowas wie curl nachbauen? Oder welches Ziel hast du?
Erstmal ist das nur Neugierde. Und ich möchte wissen, warum mein alter MediaTomb Server von einigen Programmen nicht gefunden wird. Ich sage mal so, Wenn man ein Ziel im Auge hat, arbeitet man Fachbücher ganz anders durch. Außerdem hat mich irritiert, das GUPnP AV nicht alles anzeigt, was in der XML enthalten ist. Und dann haben die XMLs auf den Servern unterschiedliche Namen. Vergleiche mal die "LOCATION:" Ausgaben in obiger Beispielausgabe.
Für XML-Parsing mit expat brauchste gute Nerven...
Mal sehen, ob ich das überhaupt mache. Jedenfalls werde ich das nicht so machen, wie in dem Script (simple-dlna-browser.sh) aus dem anderen Thread (mit sed und awk). Vielleicht wäre pugixml eine Option. P.s. Danke für den Link. Ich bräuchte zwar eher den Code für einen Client, aber zu wissen was der Server erwarte, könnte auch helfen. P.s.2 Danke auch für den zweiten Link.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6489
Wohnort: Hamburg
|
Ich glaube das letzte Beispiel hatte ich gestern auch schon gesehen (mir ist da das bzero() aufgefallen. Es geht da aber immer um ein Client und ein Server. Hier können aber mehrere Server antworten. Ich überblicke aber noch nicht ganz on das einen Unterschied macht.
|
ChickenLipsRfun2eat
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Ich habe nur ein Gerät das auf „urn:schemas-upnp-org:device:MediaServer“ reagieren kann. Ich kann aber mehrere Geräte unterschiedlicher Art abfragen: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 | #include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
int main( void ) {
unsigned char counter = 0;
const char *urns[] = {
"ST: urn:schemas-upnp-org:device:WLANAccessPointDevice:1\r\n",
"ST: urn:schemas-upnp-org:device:MediaServer:1\r\n",
"ST: upnp:rootdevice:1\r\n",
"ST: urn:schemas-upnp-org:service:ConnectionManager:1\r\n"
};
while( counter < 4 ) {
int sock,
bytes_recv;
socklen_t sin_size;
struct sockaddr_in server_addr;
struct hostent *host;
char send_data[1024],
recv_data[1024];
host = ( struct hostent * ) gethostbyname( ( char * ) "239.255.255.250" );
if( ( sock = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) {
perror("socket error");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons( 1900 );
server_addr.sin_addr = *( ( struct in_addr * ) host->h_addr );
bzero( &( server_addr.sin_zero ) ,8 );
sin_size = sizeof( struct sockaddr );
snprintf( send_data, 1024, "M-SEARCH * HTTP/1.1\r\n"
"Host: 239.255.255.250:1900\r\n"
"Man: \"ssdp:discover\"\r\n"
"%s"
"MX: 3.\r\n"
"User-Agent: gupnp-av-cp GSSDP/0.12.1\r\n", urns[counter++] );
printf( "Requesting data: %s\n", send_data );
int rv = sendto( sock, send_data, strlen(send_data), 0, (struct sockaddr *)&server_addr, sizeof( struct sockaddr ) );
printf( "bytes sent:%d\t", rv );
bytes_recv = recvfrom( sock, recv_data, 1024, 0, ( struct sockaddr * ) &server_addr, &sin_size);
printf( "bytes recv:%d\n", bytes_recv );
recv_data[bytes_recv]= '\0';
printf("Received :%s\n",recv_data);
close( sock );
}
}
|
Habe den kompletten Socket-Kram stupide mit in die Schleife gepackt, weil faul. Sockets sind ja nicht wiederbenutzbar, lässt sich aber optimieren.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6489
Wohnort: Hamburg
|
Die Sache fängt an interessant zu werden. Ich habe gerade festgestellt, dass mein Fernseher jede Menge UDP Pakete an 255.255.255.255:7776 versendet. Der erste Suchtreffer zu diesem Port sagt etwas von einer backdoor. Später wird allerdings auch erwähnt, dass viele Geräte damit nur sagen "ich bin da". Das bedeutet wahrscheinlich, das Programme, die in diesem Bereich agieren, über die ganze Laufzeit auch auf dieser Adresse lauschen müssen, um mitzubekommen wer sich da an- oder abmeldet. Und es können sich ja auch Server an- oder abmelden. Das bedeutet wohl, dass hier schonmal 2 zusätzliche Threads benötigt werden. Ich habe noch gar nicht richtig angefangen und schon ufert es aus...
Sockets sind ja nicht wiederbenutzbar, ...
Ich meine heute Morgen gelesen zu haben, dass man das durch irgendeine Einstellung ändern kann. Ich finde die Stelle jetzt aber gerade in den 6 Kapiteln nicht wieder. Hatte wohl wieder zu schnell gelesen, wegen Ungeduld. Aber deine Varianten sind interessant. Muss ich auch mal ausprobieren. Aber heute nicht mehr, es ist Krimizeit (DCI Barnaby). Ich fürchte da habe ich wieder mal einiges nicht mit gekriegt.
|
ChickenLipsRfun2eat
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Ja, das ist ja ne fixe Adresse, damit alles out of the box funktioniert. Mediareceiver, Fernseher, Handys, usw. nutzen das alle. So ne wirkliche Übersicht hab ich auf die schnelle nicht gefunden. Musste halt bei MS-SSDP anfangen und dich durch die Suchmaschinerie quälen. Falls du konkrete Ziele hast, wie bspw. Medien bereitstellen, könntest du dich am minidlna-Code orientieren. Den finde ich noch recht übersichtlich im Vergleich zu anderen. 😉
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6489
Wohnort: Hamburg
|
Falls du konkrete Ziele hast ...
Ich will erstmal nur etwas haben, was soweit funktioniert, dass man da was praxistaugliches draus machen kann. Einfach nur Text zwischen 2 Terminals hin und her schieben, reicht da nicht. Der nächste Schritt wäre jetzt, die Schleife zu bereinigen. recvfrom() blockiert, wenn nichts mehr kommt. Ich werde es man mit select() oder poll() versuchen, wobei es mir da nur um das Timeout geht. Und dann muss die XML Datei abgeholt werden. Vielleicht schaue ich mir dann noch an, was mein Fernseher alles zu erzählen hat, falls das Klartext ist.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6489
Wohnort: Hamburg
|
Ich setze das jetzt mal auf gelöst, da das ursprüngliche Problem ja gelöst ist. Trotzdem habe ich natürlich noch ein offenes Ohr für weitere Tipps. Mein aktueller Test Code ist:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 | /*
** DLNA Test, Stufe 3
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF 1024
const char * query_message =
"M-SEARCH * HTTP/1.1\r\n"
"Host: 239.255.255.250:1900\r\n"
"Man: \"ssdp:discover\"\r\n"
"ST: urn:schemas-upnp-org:device:MediaServer:1\r\n"
"MX: 3.\r\n"
"User-Agent: gupnp-av-cp GSSDP/0.12.1\r\n";
char *
get_location( const char * str ) {
const char * loc;
const char * p;
char * msg = NULL;
int cnt = 0;
if( (loc = strstr( str, "LOCATION: " )) ) {
loc += 10;
p = loc;
while( *p && *p != '\r' && *p != '\n' ) {
++p;
++cnt;
}
if( (msg = malloc( cnt + 1 )) ) {
strncpy( msg, loc, cnt );
}
return msg;
}
return NULL;
}
int
send_query( void ) {
int udp_socket; // Socket-Descriptor
char * rcv_buf = malloc( BUF );
struct sockaddr_in address;
int size;
int cnt = 0;
struct pollfd pfd[1];
struct pollfd * pollfd_ptr;;
int ready;
int loop = 1;
char * p;
if( (udp_socket = socket( AF_INET, SOCK_DGRAM, 0 )) > 0 ) {
//printf( "Socket wurde angelegt\n" );
memset( &address, 0, sizeof( address ) );
address.sin_family = AF_INET;
address.sin_port = htons( 1900 );
inet_aton( "239.255.255.250", &address.sin_addr );
pfd[0].fd = udp_socket;
pfd[0].events = POLLIN;
pfd[0].revents = 0;
pollfd_ptr = pfd;
if( sendto( udp_socket, query_message, strlen(query_message), 0, (struct sockaddr*)&address, sizeof( address ) ) > 0 ) {
while( loop ) {
ready = poll( pollfd_ptr, 1, 1000 );
switch( ready ) {
case -1:
return 0;
case 0:
loop = 0;
break;
default:
if( pfd[0].revents & POLLIN ) {
if( (size = recvfrom( udp_socket, rcv_buf, BUF-1, 0, NULL, NULL )) > 0 ) {
rcv_buf[size] = '\0';
printf( "%s\n", rcv_buf );
cnt++;
if( (p = get_location( rcv_buf )) ) {
printf( "location: %s\n", p );
}
}
}
}
}
}
}
close( udp_socket );
return cnt;
}
int
main( int argc, char **argv ) {
printf( "Received: %d\n", send_query() );
return( EXIT_SUCCESS );
}
|
Der Code zum extrahieren der XML Datei ist allerdings noch ohne Fehlerprüfung. Aber immerhin hängt das Programm jetzt nicht mehr ewig fest, wenn nichts mehr kommt.
|
snafu1
Anmeldungsdatum: 5. September 2007
Beiträge: 2133
Wohnort: Gelsenkirchen
|
Klar wird das ein erster Entwurf sein, daher bitte die Kritik am Code bitte nicht falsch verstehen. Ich stolpere jedenfalls darüber, dass query_message so weit weg von seiner Verwendung liegt. Könnte man den String nicht besser innerhalb der Funktion erstellen? Und zum anderen fällt die tiefe Verschachtelung in send_query() auf. Ich will nicht behaupten, dass ich da zu 100% durchblicke, aber die macht doch mehr als nur das Versenden, oder? Da würde ich den Empfangsteil besser irgendwie auslagern.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6489
Wohnort: Hamburg
|
Ich stolpere jedenfalls darüber, dass query_message so weit weg von seiner Verwendung liegt.
Da ich noch nicht weiß, was da alles benötigt werden könnte, wolte ich den Text bequem austauschen können. Der Name "send_query()" ist wohl tatsächlich nicht ganz zutreffend. Im Original steht da "_list_servers()". Da wird aber noch mehr gemacht. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | _list_servers() {
command -v "socat" >/dev/null 2>&1 || return 127
_lservers__query='M-SEARCH * HTTP/1.1\r
Host: 239.255.255.250:1900\r
Man: "ssdp:discover"\r
ST: urn:schemas-upnp-org:device:MediaServer:1\r
MX: 3.\r
User-Agent: gupnp-av-cp GSSDP/0.12.1\r\n'
case "${1}" in
verbose) _lservers__awk_filter='{print}' ;;
*) _lservers__awk_filter='/LOCATION/ {print $2}' ;;
esac
_lservers__results="$(printf "%b" "${_lservers__query}"| \
socat -T1 STDIO UDP4-DATAGRAM:239.255.255.250:1900 | \
tr -d '\r' | awk "${_lservers__awk_filter}")"
for _lservers__result in $(printf "%s\\n" "${_lservers__results}" | \
awk '/http/' | ${sed} 's,.*http:,http:,'); do
_lservers__friendly_name="$(printf "%s\\n" \
"$(curl -s "${_lservers__result}" 2>/dev/null || \
wget -q -O- "${_lservers__result}" 2>/dev/null)" | \
${sed} 's:</:\n:g' | \
awk '/<friendlyName/ {gsub(/.*<friendlyName>/,""); print}')"
_lservers__results="$(printf "%s\\n" "${_lservers__results}" | \
${sed} "s,${_lservers__result},${_lservers__result} (${_lservers__friendly_name}),")"
done
printf "%s\\n" "${_lservers__results}"
}
|
Das ist aus: simple-dlna-browser.sh
Da würde ich den Empfangsteil besser irgendwie auslagern.
Damit hätte ich ein Problem. Bisher gehe ich davon aus, das diese Funktion nur selten gebraucht wird, z.B. beim Programmstart. Daher schließe ich den UDP Filededscriptor wieder. Danach kann ich von "239.255.255.250" nichts mehr empfangen. Die tiefe Verschachtelung kann man sicher vermeiden, wenn man das Timeout Problem anders löst. Danach geht es wahrscheinlich mit TCP weiter. Wobei ich wohl nebenbei noch weiter auf 255.255.255.255 (Broadcasts) achten müsste. Dazu habe ich aber noch keine Idee. P.s. Das ist eigentlich noch nicht mal ein Entwurf. Ein Entwurf setzt voraus, dass man mindestens eine Idee davon hat, was man brauchen könnte. Momentan ist das nur ein Vortasten um ein Gefühl für die Thematik zu bekommen.
|
ChickenLipsRfun2eat
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Wenn du aber neue oder neu gestartete Geräte mitverwalten willst, müsstest du das entweder regelmäßig selbst abfragen, oder das ewige Warten auf neue Events in einen Thread auslagern. Ich weiß auch nicht, was da so an Events verteilt wird, die bspw. das einpflegen neuer Dateien, etc.
|