2010-05-21 12 views
7

Czy można użyć recvmsg() w celu uzyskania pola IP_TOS dla każdego przychodzącego pakietu lub po prostu pokazuje wartość IP_TOS, która jest ustawiona dla danego gniazda. Jeśli nie, czy ktoś wie o rozwiązaniu, aby uzyskać wartości IP_TOS dla każdego przychodzącego pakietu. Używam aplikacji UDP i dlatego nie widzę pola IP_TOS na warstwie aplikacji, tak jak ma to miejsce w przypadku TCP. Dzięki.Linux: Czy Recvmsg może być użyty do odbierania IP_TOS każdego przychodzącego pakietu

Dodanie kodu, który napisałem do tej pory, okrywać pomaga:

struct msghdr msg; 
struct iovec iov[1]; 
memset(&msg, '\0', sizeof(msg)); 
msg.msg_iov = iov; 
msg.msg_iovlen = 1; 
iov[0].iov_base = (char *) &pkt; 
iov[0].iov_len = sizeof(pkt); 

struct cmsghdr cmsgcmsg[1]; 
msg.msg_control = cmsgcmsg; 
msg.msg_controllen = sizeof(struct cmsghdr); 


nRet = recvmsg(udpSocket, &msg, 0); 

if (nRet > 0) { 
    struct cmsghdr *cmsg; 
    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) { 

    if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_TOS) && 
    (cmsg->cmsg_len)){ 
       int tos = *(uint8_t *)CMSG_DATA(cmsg); 
       int isecn = ((tos & INET_ECN_MASK) == INET_ECN_CE); 
      printf("the tos = %i , is ecn = %d \n", tos, isecn); 

    } 
    } 

Odpowiedz

0

Zwykle dostęp do pola ToS poprzez getsockopt()/setsockopt(), ale wydaje się być very implementation dependent. Czasami warto rozejrzeć do_ip_setsockopt() w źródłach jądra w drzewie jądra Linux w linux/net/ipv4/ip_sockglue.c

Twój najlepszy przyjaciel w nawigacji źródło jest there.

+1

Dzięki. O ile mi wiadomo, wydaje się, że setsockopt()/getsockopt() są używane do ustawiania i pobierania opcji, które można ustawić na wychodzących pakietach, podczas gdy setsockopt (IPPROTO_IP) + recvmesg() może być używany do odczytu IP_TOS i inne IP_OPTIONS przychodzących pakietów. Kod wydaje mi się jednak zawodzić, a wszystko, co dostaję, to niektóre wartości śmieci. – Mayutan

8

W końcu udało mi się rozwiązać problem i dodałem tutaj kod, aby inni mogli go użyć. Mam nadzieję, że pomoże to innym. Ten jest dla IP_TTL:

Ustaw UDPSocket aby otrzymać wartości IP_TTL:

int ttl = 60; 
if(setsockopt(udpSocket, IPPROTO_IP, IP_RECVTTL, &ttl,sizeof(ttl))<0) 
{ 
    printf("cannot set recvttl\n"); 
} 
else 
{ 
    printf("socket set to recvttl\n"); 
} 

i pobierać wartości IP_TTL z każdego pakietu w następujący sposób (Poniższy program może pobrać wiadomość z danymi poprzez IOV [0 ] Fragment kodu poniżej):

struct msghdr msg; 
struct iovec iov[1]; 
memset(&msg, '\0', sizeof(msg)); 
msg.msg_iov = iov; 
msg.msg_iovlen = 1; 
iov[0].iov_base = (char *) &pkt; 
iov[0].iov_len = sizeof(pkt); 

int *ttlptr=NULL; 
int received_ttl = 0; 

int cmsg_size = sizeof(struct cmsghdr)+sizeof(received_ttl); // NOTE: Size of header + size of data 
char buf[CMSG_SPACE(sizeof(received_ttl))]; 
msg.msg_control = buf; // Assign buffer space for control header + header data/value 
msg.msg_controllen = sizeof(buf); //just initializing it 

nRet = recvmsg(udpSocket, &msg, 0); 



if (nRet > 0) { 
    struct cmsghdr *cmsg; 
    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) { 

      if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_TTL) && 
      (cmsg->cmsg_len)){ 
       ttlptr = (int *) CMSG_DATA(cmsg); 
       received_ttl = *ttlptr; 
       printf("received_ttl = %i and %d \n", ttlptr, received_ttl); 
       break; 
      } 
    } 
} 

dane komunikatu mogą być wysyłane i otrzymuje się w następujący sposób:

stronie nadawcy:

struct DATA_to_SEND pkt; 
struct msghdr msg; 
struct iovec iov[1]; 
memset(&msg, '\0', sizeof(msg)); 
msg.msg_iov = iov; 
msg.msg_iovlen = 1; 
iov[0].iov_base = (char *) &pkt; 
iov[0].iov_len = sizeof(pkt); 
nRet = sendmsg(udpSocket, &msg,0); 

Odbiornik boczna (założenie DATA_To_SEND ma parametr o nazwie "nast"):

struct DATA_to_SEND pkt; 
seqNum = ((struct DATA_to_SEND *) iov[0].iov_base)->seq; 

Poniżej jest dla IP_TOS. Ustaw gniazdo otrzymywać IP_TOS:

unsigned char set = 0x03; 
if(setsockopt(udpSocket, IPPROTO_IP, IP_RECVTOS, &set,sizeof(set))<0) 
{ 
    printf("cannot set recvtos\n"); 
} 
else 
{ 
     printf("socket set to recvtos\n"); 

i pobrać wartość IP_TOS z każdego nagłówka pakietu przez:

struct PC_Pkt pkt; 
int *ecnptr; 
unsigned char received_ecn; 

struct msghdr msg; 
struct iovec iov[1]; 
memset(&msg, '\0', sizeof(msg)); 
msg.msg_iov = iov; 
msg.msg_iovlen = 1; 
iov[0].iov_base = (char *) &pkt; 
iov[0].iov_len = sizeof(pkt); 

int cmsg_size = sizeof(struct cmsghdr)+sizeof(received_ecn); 
char buf[CMSG_SPACE(sizeof(received_ecn))]; 
msg.msg_control = buf; 
msg.msg_controllen = sizeof(buf); 

nRet = recvmsg(udpSocket, &msg, 0); 

if (nRet > 0) { 
struct cmsghdr *cmsg; 
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 
cmsg = CMSG_NXTHDR(&msg,cmsg)) { 
     if ((cmsg->cmsg_level == IPPROTO_IP) && 
     (cmsg->cmsg_type == IP_TOS) && (cmsg->cmsg_len)){ 
       ecnptr = (int *) CMSG_DATA(cmsg); 
     received_ecn = *ecnptr; 
     int isecn = ((received_ecn & INET_ECN_MASK) == INET_ECN_CE); 

       printf("received_ecn = %i and %d, is ECN CE marked = %d \n", ecnptr, received_ecn, isecn); 

       break; 
    } 
    } 
} 
+1

Podwaj za udostępnienie kodu rozwiązania. –

+0

o czym jest ta ttl = 60 magiczna liczba? –

1

stworzyłem prosty przykład wykorzystania i setsockopt() wysłać ECN zdolnych pakiety i inne bity ECN z otrzymanych pakietów przy użyciu recvmsg() oraz getsockopt(). Można go znaleźć pod adresem:

https://gist.github.com/jirihnidek/95c369996a81be1b854e

Korzystanie getsockopt() prawdopodobnie nie będzie działać na innych platformach następnie Linux, ale można go używać z recv() i recvfrom() funkcji.

BTW: INET_ECN_MASK, INET_ECN_CE itp. Nie są zdefiniowane w in.h.W związku z tym konieczne będzie uwzględnienie nagłówków jądra systemu Linux (przekroczenie IMHO) lub można (ponownie) zdefiniować własne stałe:

#define INET_ECN_NOT_ECT 0x00 /* ECN was not enabled */ 
#define INET_ECN_ECT_1  0x01 /* ECN capable packet */ 
#define INET_ECN_ECT_0  0x02 /* ECN capable packet */ 
#define INET_ECN_CE   0x03 /* ECN congestion */ 
#define INET_ECN_MASK  0x03 /* Mask of ECN bits */ 
+0

Holy crap, przyzwoity przykład użycia 'recvmsg()'. Dzięki wielkie! –

Powiązane problemy