Roh -Ethernet -Socket -Blöcke beim Recv -Aufruf mit anhängigen DatenLinux

Linux verstehen
Guest
 Roh -Ethernet -Socket -Blöcke beim Recv -Aufruf mit anhängigen Daten

Post by Guest »

Ich arbeite mit Raw -Ethernet -Sockets und erlebe ein seltsames Problem, bei dem ein Senden /

Code: Select all

send
/

Code: Select all

recv
/

Code: Select all

recv
/Wiederholungsmuster kann zum endgültigen Recv auf unbestimmte Zeit blockieren. class = "Lang-C PrettyPrint-Override">

Code: Select all

sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
zusammen mit dem Promiscuous -Modus auf der Schnittstelle, auf die ich sende und empfange

Code: Select all

recv
/Wiederholungsszenario funktioniert wie erwartet :
Ich habe eine Ping/Pong und Kasten A und B sind durch ein einzelnes Ethernet -Kabel miteinander verbunden:
App A :

Code: Select all

while (1) {
// Send PING + pass sockaddr_ll with interface info
sendto(...);
// Block until PONG is received + logic to ignore irrelevant traffic
recv(...);
}
App B :

Code: Select all

while (1) {
// Block until we recv a PING + logic to ignore irrelevant traffic
recv(...);
// Reply with a PONG + pass sockaddr_ll with interface info
sendto(...);
}
< /code>
Wie erwähnt, funktioniert dies alles einwandfrei. Das [url=viewtopic.php?t=11587]Problem[/url] tritt auf, wenn ich App [b] a [/b] zu:
änderewhile (1) {
sendto(...); // PING 1
sendto(...); // PING 2
recv(...); // PONG 1
recv(...); // PONG 2?
}
< /code>
Einige wichtige Beobachtungen: < /p>

[*]  Der zweite Aufruf zu recv < /code> kann einfach unbegrenzt blockieren. Je mehr Sie es schleifen lassen, desto wahrscheinlicher wird es passieren, tritt jedoch normalerweise innerhalb der ersten 10-20 Iterationen auf. < /P>
< /li>
  Ich dachte es Könnte nur einen schlechten Code sein, aber wenn ich die Schnittstelle in Box A mit TCPDump überwachte, wird auch TCPDump nicht berichtet, dass der Frame auf der Schnittstelle angezeigt wird. Nachdem Sie einige Sekunden gewartet und Strg+C in App A gedrückt haben, meldet das Ausführen von ifConfig  
einen neuen fallengelassenen Frame auf der Schnittstelle.

< LI> Ich weiß, dass Kasten B mit der Pong antwortet, weil ich die Hardware zur Netzwerküberwachung verwendet habe, um die Antworten von b -> A auf ein separates Feld C und TCPDump auf C -Berichten zu spiegeln Pong. Ich denke nicht (?) Es ist nur ein Problem mit Kasten a. der zweite recv und ich verwende Ein separates Programm zum Senden eines beliebigen nicht-pongischen Frame an derselben Schnittstelle und über die Kabel, auf die App A+B kommunizieren, und dann wird es den letzten Pong durchsetzen und App A wird auf recv aufhören zu blockieren . Ich kann dies entweder aus Kasten A oder Kasten B tun, solange es an die Schnittstelle des Subjekts gesendet wird, und es wird es immer noch "treten". Es braucht nur einen Datenverkehr, um es durchzusetzen. Schnittstelle, aber schließlich bleibt wieder stecken. > Nur App A , senden Sie diese Das erste "Ping" wird die Schnittstelle "treten" und die erste Pong, die es erhält, wird das sein, das bisher nirgends aus dem letzten Lauf zu finden war. < /p>
< /li>
< LI> Sendungsgeschwindigkeit kann etwas damit zu tun haben. Wenn ich die Schleife entferne und App eine von Hand wiederholt neu ausführte, wird es nicht geschehen (oder ich habe sie noch nicht gesehen). Deshalb habe ich sie auf einer Schleife. Aber logischerweise sollten auf dem Draht jeweils nur 2 Frames anhängig sein? Was ich hier erlebe? Scheint, als würden sich der Kernel oder sogar die NIC nur am Rahmen festhalten und nicht loslassen, bis etwas anderes dahinter ihn durchträgt? Ich glaube nicht, dass es Nagles Algorithmus sein kann, weil ich mich mit RAW -Ethernet -Rahmen und nicht mit TCP zu beschäftigen kann. Die Tatsache, dass selbst TCPDump nicht berichtet, dass der verlorene Rahmen umwerfend ist. Schlechte NICs auf beiden Boxen (siehe Punkt 4)? Wie kann ich das weiter debuggen? Sie müssen den Promiscuous -Modus selbst aktivieren, indem Sie IP -Link -Set -Dev on .
ausführen

Code: Select all

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define PING "PING"
#define PONG "PONG"
// To send full PXNG + null terminator
#define DATALEN 5
#define min(x, y) (x > y ? y : x)
#define be_u16(x) ((uint16_t)(((x >> 8) & 0xFF) | ((x & 0xFF) ifa_name, iface_name, IF_NAMESIZE) == 0 &&
(ifaddr->ifa_flags & IFF_UP) > 0 &&
ifaddr->ifa_addr &&
ifaddr->ifa_addr->sa_family == AF_PACKET)
break;

ifaddr = ifaddr->ifa_next;
}

if (!ifaddr)
{
fprintf(stderr, "device not found\n");
return -1;
}

// Copy sockaddr info into out-pointer
memcpy(sockaddr, (struct sockaddr_ll *)ifaddr->ifa_addr, sizeof(*sockaddr));

freeifaddrs(ifaddrs);

// Create the actual socket
if ((*sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
{
perror("socket");
return -1;
}

// And bind it to our interface
if (bind(*sock, (struct sockaddr *)sockaddr, sizeof(*sockaddr)) < 0)
{
perror("bind");
return -1;
}

// User should enable promisc mode on interface
// $ ip link set dev  promisc on

return 0;
}

// Send a PING or a PONG (whichever `data` is)
int32_t tx_pxng(char *data, size_t len, int32_t sock, struct sockaddr_ll *sockaddr)
{
if (sendto(sock, data, len, 0, (struct sockaddr *)sockaddr, sizeof(*sockaddr)) < 0)
{
perror("sendto");
return -1;
}

// Acknowledge send
if (len > ETH_HLEN)
printf("%s\n", data + ETH_HLEN);

return 0;
}

// Wait for a PING or a PONG (whichever `data` is)
int32_t rx_pxng(char *data, size_t len, int32_t sock, char *buf, size_t buf_len)
{
int32_t read;

rx:
if ((read = recv(sock, buf, buf_len, 0)) < 0)
{
perror("recv");
return -1;
}

// Filter out irrelevant traffic
if (read < ETH_HLEN || memcmp(data, buf + ETH_HLEN, min((size_t)read - ETH_HLEN, len)) != 0)
goto rx;

// Acknowledge receive
printf("%s\n", data);

return 0;
}

ssize_t init_send_buffer(char *buf, size_t buf_len, char *payload, size_t payload_len, struct sockaddr_ll *sockaddr)
{
// Init socket with payload + `sockaddr` address info
if (buf_len < ETH_HLEN + payload_len)
return -1;

// Fill in `src` field
memcpy(buf + ETH_ALEN, sockaddr->sll_addr, ETH_ALEN);

// Write in length field as BE uint16 (values < 1500 should be cosnidered length)
uint16_t *len_ptr = (uint16_t *)(buf + (2 * ETH_ALEN));
*len_ptr = be_u16((uint16_t)payload_len);

// Copy in payload
memcpy(buf + ETH_HLEN, payload, payload_len);

// Return total written length
return ETH_HLEN + payload_len;
}

int32_t pingpong(char *iface_name, bool ping_side)
{
int32_t sock;
struct sockaddr_ll sockaddr = {0};

// Basic socket initialization
if (init_socket(&sock, &sockaddr, iface_name) <  0)
return EXIT_FAILURE;

// Setup and init send buffer + create recv buffer
char *send_buf = calloc(ETH_FRAME_LEN, 1);
char *recv_buf = calloc(ETH_FRAME_LEN, 1);

ssize_t send_len;
char *payload = ping_side ? PING : PONG;

if ((send_len = init_send_buffer(send_buf, ETH_FRAME_LEN, payload, DATALEN, &sockaddr)) < 0)
return EXIT_FAILURE;

if (ping_side)
{
// PING-ing side - App A
while (1)
{
// Send PING 1
if (tx_pxng(send_buf, send_len, sock, &sockaddr) < 0)
return EXIT_FAILURE;

// Send PING 2
if (tx_pxng(send_buf, send_len, sock, &sockaddr) < 0)
return EXIT_FAILURE;

// Wait for PONG 1
if (rx_pxng(PONG, DATALEN, sock, recv_buf, ETH_FRAME_LEN) < 0)
return EXIT_FAILURE;

// Wait for PONG 2 - May block indefinitely???
// Even tcpdump sees nothing...
if (rx_pxng(PONG, DATALEN, sock, recv_buf, ETH_FRAME_LEN) < 0)
return EXIT_FAILURE;
}
}
else
{
// PONG-ing side - App B
while (1)
{
// Expect a PING
if (rx_pxng(PING, DATALEN, sock, recv_buf, ETH_FRAME_LEN) < 0)
return EXIT_FAILURE;

// Reply with PONG
if (tx_pxng(send_buf, send_len, sock, &sockaddr) < 0)
return EXIT_FAILURE;
}
}

return EXIT_SUCCESS;
}

int32_t main(int32_t argc, char *argv[])
{
char *interface_name = NULL;
bool ping_side = true;

char opt;

while ((opt = getopt(argc, argv, "i:ab")) != -1)
{
switch (opt)
{
case 'i':
interface_name = optarg;
break;
case 'a':
ping_side = true;
break;
case 'b':
ping_side = false;
break;
default:
usage();
return 0;
}
}

return pingpong(interface_name, ping_side);
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post