» »

[c]recvmsg

[c]recvmsg

slovencl ::

Berem dokumentacijo in gledam primere uporabe recvmsg(), ampak enostavno ne štekam, kako sploh prideš do vsebine ethernet paketa?

Za osnovo sem vzel enega od teh primerov. Recvmsg mi sicer vrne število bytov, ki so bili sprejeti. Imam pa raw socket sockfd = socket(PF_PACKET, SOCK_RAW, htons(0x1234)).

Kakšna ideja?
  • spremenil: slovencl ()

Mavrik ::

Saj mu podaš buffer v kerega bo dal podatke kot parameter a ne?
The truth is rarely pure and never simple.

slovencl ::

tale koda:
int read_size = 200; //10 * 1024;                                                                                                                                                                   
  const int CMSG_SIZE = 1024;
  unsigned char cmsg_buf[CMSG_SIZE];
  struct iovec recv_iov;
  struct cmsghdr *cmsg;
  bool failed = false;
  struct msghdr hdr;
  int flags = 0;
  int r;

  memset(&hdr, 0, sizeof(hdr));
  hdr.msg_iov = &recv_iov;
  hdr.msg_iovlen = 1;
  recv_iov.iov_base = malloc(read_size);
  recv_iov.iov_len = read_size;
  hdr.msg_control = cmsg_buf;
  hdr.msg_controllen = sizeof(cmsg_buf);

  r = recvmsg(rcv, &hdr, flags);
  if (r < 0) { perror("Failed to recvmsg: "); }
  if (r != 0) { fprintf(stderr, "rx payload: %d B.\n", r); }
  if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { perror("Message was truncated.\n"); }

  for(int i=0; i<r+100; i++) { fprintf(stderr, "%02x:", cmsg_buf[i]); } fprintf(stderr, "\n");

  // Get the address of the first 'cmsghdr' in the received ancillary data                                                                                                                            
  cmsg = CMSG_FIRSTHDR(&hdr);


  // Check the validity of the 'cmsghdr'                                                                                                                                                              
  if (cmsg == NULL) { fprintf(stderr, "cmsg null \n"); }



mi vrne:
rx payload: 64 B.
c8:94:4e:37:c3:7f:00:00:28:eb:62:35:fc:7f:00:00:e0:4c:4c:37:c3:7f:00:00:70:91:4e:37:c3:7f:00:00:00:00:00:00:00:00:00:00:ef:b1:2c:37:c3:7f:00:00:08:00:00:00:00:00:00:00:e0:4c:4c:37:c3:7f:00:00:01:00:00:00:00:00:00:00:00:6a:17:0d:e8:52:bf:c1:70:ea:62:35:fc:7f:00:00:70:ea:62:35:fc:7f:00:00:2f:00:00:00:00:00:00:00:0d:6a:b2:35:c3:7f:00:00:e8:eb:62:35:fc:7f:00:00:80:87:d2:35:c3:7f:00:00:94:a9:4b:37:c3:7f:00:00:10:89:db:35:c3:7f:00:00:01:80:ad:fb:00:00:00:00:94:a9:4b:37:c3:7f:00:00:94:a9:4b:37:
cmsg null


dejansko pa je v paketku:
0010  10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f   ................
0020  20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f    !"#$%&'()*+,-./
0030  30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f   0123456789:;<=>?

AndrejO ::

cmsg_buf[i])


To si opazil, da si izpisuješ dodatne podatke iz protokola in ne vsebino paketa? Vsebino paketa boš našel v recv_iov.iov_base.
28.3 čl. Pravil: Argumentirano pritožbo mora uporabnik poslati v oddelek
Slo-Tech, tema Pritožbe. Pritožb poslanih po zasebnih sporočilih,
elektronski pošti ali odprte v obliki tem v drugih oddelkih se ne upošteva.

slovencl ::

Sem poskusil tudi to, da izpiše iov, pa še vedno dobivam neke čudne podatke:
int read_size = 200; //10 * 1024;                                                                                                                                                                          
  const int CMSG_SIZE = 1024;
  unsigned char cmsg_buf[CMSG_SIZE];
  struct iovec recv_iov;
  struct cmsghdr *cmsg;
  bool failed = false;
  struct msghdr hdr;
  int flags = 0;
  int r;

  unsigned char imsg_buf[100];
  recv_iov.iov_base = imsg_buf;
  recv_iov.iov_len = 100;

  memset(&hdr, 0, sizeof(hdr));
  hdr.msg_iov = &recv_iov;
  hdr.msg_iovlen = 1;
  recv_iov.iov_base = malloc(read_size);
  recv_iov.iov_len = read_size;
  hdr.msg_control = cmsg_buf;
  hdr.msg_controllen = sizeof(cmsg_buf);

  r = recvmsg(rcv, &hdr, flags);
  if (r < 0) { perror("Failed to recvmsg: "); }
  if (r != 0) { fprintf(stderr, "rx payload: %d B.\n", r); }
  if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { perror("Message was truncated.\n"); }

fprintf(stderr, "I MSG "); for(int i=0; i<r; i++) { fprintf(stderr, "%02x:", imsg_buf[i]); } fprintf(stderr, "\n");


Mi vrne:
I MSG 00:00:00:00:00:12:7b:c2:ce:ba:01:16:70:5e:58:59:fd:7f:00:00:d3:94:dc:fd:a8:7f:00:00:d0:5e:58:59:fd:7f:00:00:40:b4:fc:fd:a8:7f:00:00:00:01:00:00:00:00:00:00:50:b5:fc:fd:a8:7f:00:00:14:00:00:00: 


paket ki ga sprejme je še vedno isti (posneto z wireshark):
0010  10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f   ................
0020  20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f    !"#$%&'()*+,-./
0030  30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f   0123456789:;<=>?

Senitel ::

imsg_buf je garbage, sej nič ne daš notri. Stuff je dejansko v recv_iov.iov_base, ki ga alociraš tukaj recv_iov.iov_base = malloc(read_size);.

Randomness ::

recv_iov.iov_base = imsg_buf;
recv_iov.iov_len = 100;

// tukaj si povoziš recv_iov
recv_iov.iov_base = malloc(read_size);
recv_iov.iov_len = read_size;

slovencl ::

Super, najlepša hvala, tole sem pa spregledal... tale del zgoraj mi zdej dela.

Imam pa še vedno problem, da mi cmsg vrača NULL. Koda je enako povzeta od enega od primerov. Mogoče kdo ve zakaj?
 struct cmsghdr *cmsg;
  union {
    struct cmsghdr hdr;
    unsigned char buf[CMSG_SPACE(sizeof(int))];
  } cmsgbuf;

  struct iovec recv_iov;
  struct msghdr hdr;
  int r;

  unsigned char imsg_bufmemset(&hdr, 0, sizeof(hdr));
  hdr.msg_iov = &recv_iov;
  hdr.msg_iovlen = 1;
  recv_iov.iov_base = imsg_buf; //recv_iov.iov_base = malloc(read_size);                                                                                                                                     
  recv_iov.iov_len = 2048; //recv_iov.iov_len = read_size;                                                                                                                                                   
  hdr.msg_control = &cmsgbuf.buf;
  hdr.msg_controllen = sizeof(cmsgbuf.buf);

  r = recvmsg(rcv, &hdr, 0);
  if (r < 0) { perror("Failed to recvmsg: "); }
  if (r != 0) { fprintf(stderr, "rx payload: %d B.\n", r); }
  if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { perror("Message was truncated.\n"); }

// Get the address of the first 'cmsghdr' in the received ancillary data                                                                                                                                   
  cmsg = CMSG_FIRSTHDR(&hdr);
// Check the validity of the 'cmsghdr'                                                                                                                                                                     
  if (cmsg == NULL) { fprintf(stderr, "cmsg null \n"); }


Mi vrača
cmsg null

Zgodovina sprememb…

  • spremenil: slovencl ()

Randomness ::

Kaj sploh želiš doseči? Veš, za kaj se uporablja "ancillary data mechanism"?

slovencl ::

Uporablja se za to, da dobiš podatke o paketu, ki niso sama vsebina paketa, mar ne?
Jaz bi rad prebral timestamp paketa. Sem tudi vključil to funkcijo s setsockopt.

Ampak verjetno "ancillary data" tudi če nič ne vključiš preko setsockopt nikoli niso NULL?
Glede na opis CMSG_FIRSTHDR(): It returns NULL if there isn't enough space for a cmsghdr in the buffer. Koliko pa potrebuje?

Zgodovina sprememb…

  • spremenil: slovencl ()

Randomness ::

Ni nujno, da vsak paket vsebuje dodatne podatke. Če bi bil buffer premajhen, bi dobil izpis "Message was truncated.", saj preverjaš msg_flags. Ne vem točno, kaj čaraš, ampak koda na tem linku izpisuje timestampe paketov.

Svetujem ti, da si pogledaš libpcap, ki ga uporablja tudi Wireshark.

slovencl ::

Aha, najlepša hvala ti za tole... tole tudi meni deluje. Če pa izpustim setsockopt, pa mi cmsg ravno tako vrne NULL.

Očitno imam narobe nastavljen setsockopt, rad bi namreč imel harverski timestamp. Takole imam nastavljeno:
  int opt= 0;
  opt |= SOF_TIMESTAMPING_RX_HARDWARE;
  opt |= SOF_TIMESTAMPING_RAW_HARDWARE;
  if (setsockopt(sockfd, SOL_SOCKET, SO_TIMESTAMPING, (char *)&opt, sizeof(opt))) {
    perror("setsockopt timestamping");
    close(sockfd);
    exit(EXIT_FAILURE);
  }


Ali imaš idejo v čem bi lahko bil problem s temi nastavitvami? Če prav razumem wireshark podpira samo softverski timestamp.

Hardver mi timestamping podpira:
Time stamping parameters for enp3s0:
Capabilities:
hardware-transmit (SOF_TIMESTAMPING_TX_HARDWARE)
software-transmit (SOF_TIMESTAMPING_TX_SOFTWARE)
hardware-receive (SOF_TIMESTAMPING_RX_HARDWARE)
software-receive (SOF_TIMESTAMPING_RX_SOFTWARE)
software-system-clock (SOF_TIMESTAMPING_SOFTWARE)
hardware-raw-clock (SOF_TIMESTAMPING_RAW_HARDWARE)
PTP Hardware Clock: 0
Hardware Transmit Timestamp Modes:
off (HWTSTAMP_TX_OFF)
on (HWTSTAMP_TX_ON)
Hardware Receive Filter Modes:
none (HWTSTAMP_FILTER_NONE)
all (HWTSTAMP_FILTER_ALL)

Zgodovina sprememb…

  • spremenil: slovencl ()

Randomness ::

Na interfaceu moraš vklopiti HW timestampanje. Glej ioctl in SIOCSHWTSTAMP.
Če prav razumem wireshark podpira samo softverski timestamp.

Ne, Wireshark podpira to, kar podpira libpcap. Poleg nastavljanja HW filtrov tudi HW timestampe.

Zgodovina sprememb…

slovencl ::

@Randomness: Carsko, sem preizkusil in na prvi pogled zgleda da deluje! :) Res najlepša ti hvala za tele nasvete!


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[c] ne sprejme UDP paketa

Oddelek: Programiranje
7984 (572) slovencl
»

[C++] problem z binarnimi datotekami

Oddelek: Programiranje
9944 (809) mallard
»

SMTP v c -ju

Oddelek: Programiranje
282119 (1260) BigWhale
»

[ C ] floating point not loaded !!?

Oddelek: Programiranje
111558 (1491) Fizikalko
»

Delo z omrezjem v linuxu

Oddelek: Programiranje
101296 (1142) CCfly

Več podobnih tem