2017-03-06 1 views
0

커널 2.6.18 인 Linux에서 sendmsg()를 사용하여 설정된 TOS 값으로 UDP 패킷을 보내려고합니다. 그러나 '잘못된 인수'오류로 호출이 실패합니다. 부수적 인 데이터 부분을 비활성화하면 (조건 컴파일 플래그 USE_IP_TOS 참조) sendmsg()가 성공합니다. 코드와 출력은 다음 것은 :sendmsg()가 IP_TOS 보조 데이터와 함께 UDP 패킷을 보내는 동안 실패 함

#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <errno.h> 
#include <sys/ioctl.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <sys/epoll.h> 
#include <net/if.h> 

#define UDP_PORT 45897 

int SendMsgWithIPTOS(int sockfd, unsigned char *pBuf, size_t bufLen, int tos) 
{ 
    unsigned int toIp; 
    struct sockaddr_in to_addr; 

    struct msghdr msg; 
    struct iovec iov[1]; 
    unsigned char cmsg[ CMSG_SPACE(sizeof(int)) ]; 
    struct cmsghdr *cmsgptr = NULL; 

    size_t sendBytes = 0; 

    toIp = 0x0a214401; 
    to_addr.sin_addr.s_addr = htonl(toIp); 
    to_addr.sin_family = AF_INET; 
    to_addr.sin_port = htons(UDP_PORT); 

    memset(&iov, 0, sizeof(iov)); 
    memset(&cmsg, 0, sizeof(cmsg)); 

    iov[0].iov_base = pBuf; 
    iov[0].iov_len = bufLen; 

    memset(&msg, 0, sizeof (struct msghdr)); 
    msg.msg_name = &to_addr; 
    msg.msg_namelen = sizeof(to_addr); 
    msg.msg_iov = iov; 
    msg.msg_iovlen = 1; 

#ifndef USE_IP_TOS 
    msg.msg_control = NULL; 
    msg.msg_controllen = 0; 
#else 
    msg.msg_control = cmsg; 
    msg.msg_controllen = sizeof(cmsg); 
    cmsgptr = CMSG_FIRSTHDR(&msg); 
    cmsgptr->cmsg_level = IPPROTO_IP; 
    cmsgptr->cmsg_type = IP_TOS; 
    cmsgptr->cmsg_len = CMSG_LEN(sizeof(int)); 
    memcpy(CMSG_DATA(cmsgptr), (unsigned char*)&tos, sizeof(int)); 
    //*((int *) CMSG_DATA (cmsgptr)) = tos; 
    msg.msg_controllen = CMSG_SPACE(sizeof(int)); 
#endif 

    msg.msg_flags = 0; 

    if ((sendBytes = sendmsg(sockfd, &msg, 0)) == -1) 
    { 
     fprintf(stderr, "sendmsg() failed (%s) (%d)\n", strerror(errno), errno); 
    } 
    else 
    { 
     fprintf(stderr, "sent %d bytes \n", sendBytes); 
    } 

    return sendBytes; 
} 

int main() 
{ 
    int32_t sockfd, retCode; 
    struct sockaddr_in sockaddr; 
    socklen_t addrlen = sizeof(sockaddr); 
    unsigned char buf[1024] = { 0 }; 
    size_t len = sizeof(buf); 
    int optval; 

    /* Create a UDP socket */ 
    if((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 
    { 
     fprintf(stderr, "socket failed (%s)\n", strerror(errno)); 
     return sockfd; 
    } 

    /* Bind the socket to the given port */ 
    memset(&sockaddr, 0, addrlen); 
    sockaddr.sin_addr.s_addr = INADDR_ANY; 
    sockaddr.sin_family = AF_INET; 
    sockaddr.sin_port = htons(UDP_PORT); 

    if ((retCode = bind(sockfd, (const struct sockaddr *)&sockaddr, addrlen)) < 0) 
    { 
     fprintf(stderr, "bind failed (%s)\n", strerror(errno)); 
     close(sockfd); 
     return retCode; 
    } 

#if 0 // set the DSCP value using setsockopt 
    /* Set the DSCP value to Expedited Forwarding (0x2e) */ 
    optval = 0xb8; 
    if (setsockopt(sockfd, IPPROTO_IP, IP_TOS, (void*)&optval, sizeof(optval)) < 0) 
    { 
     fprintf(stderr, "Failed to set DSCP value (%s)\n", strerror(errno)); 
     close(sockfd); 
     return retCode; 
    } 
    else 
    { 
     socklen_t optlen = sizeof(optval); 
     fprintf(stderr, "DSCP value to set to %u\n", (optval >> 2)); 
     optval = 0; 
     if (getsockopt(sockfd, IPPROTO_IP, IP_TOS, (void*)&optval, &optlen) < 0) 
     { 
      fprintf(stderr, "Failed to retrieve ip_tos value\n"); 
     } 
     else 
     { 
      fprintf(stderr, "Retrieved dscp value %u optlen (%d)\n", (optval >> 2), optlen); 
     } 
    } 
#endif 

    optval = 0xb8; // Expedited Forwarding 
    while (1) 
    { 
     retCode = SendMsgWithIPTOS(sockfd, buf, len, optval); 
     sleep(1); 
    } 

    return retCode; 
} 

Output: 
------- 
$ 
$ gcc -o ip_tos sockopt_test.c -Wall -DUSE_IP_TOS 
$ 
$ ./ip_tos 
sendmsg() failed (Invalid argument) (22) 
sendmsg() failed (Invalid argument) (22) 

$ 
$ gcc -o ip_tos sockopt_test.c -Wall 
sockopt_test.c: In function ‘SendMsgWithIPTOS’: 
sockopt_test.c:22: warning: unused variable ‘cmsgptr’ 
$ 
$ ./ip_tos 
sent 1024 bytes 
sent 1024 bytes 

$ 

내가 테스트 목적을 위해 코드의 setsockopt를() 부분을 활성화/비활성화 시도 유의하시기 바랍니다. 하지만 그게 도움이되지 않습니다

내가 뭘 잘못하고 있는지 모르겠어. 코드를 사용하여 문제를 찾는 데 도움이되거나 문제를 디버깅하는 데 도움이되는 포인터를 제공해 주시면 대단히 감사하겠습니다.

감사 Raveendra

답변

-1

내가 약간 (2 명 변경 : 다른 IP와 매크로 USE_IP_TOS 정의를) 변경 코드를 시도 내를 CentOS [커널 = 3.10.0] => 윈도우 테스트 sendings에, - 그것은 작동합니다. 나는 DSCP 필드가 '신속 전달'으로 설정된 Wireshark UPD 패킷을 보았습니다.

코드가 작동합니다.

서명 된 sys-call 반환 값에는 부호없는 변수 [size_t sendBytes]를 사용할 수 없습니다. memset-s도 쓸모가 없습니다. 아마도 보안상의 이유로 (이상한 errno) 문제가 발생했을 수 있습니다. 또는 커널이 너무 오래되었습니다. 또는이 기능의 지원은 커널에서 컴파일됩니다. EINVAL로 시스템이 나쁜 ToS (예 : = 2)에 대해 불만을 표시 할 수 있습니다.

+1

코드를 어떻게 변경 했습니까? 귀하의 답변을 수정하십시오. –

+1

이 질문에 대한 답을 제공하지 않습니다. 충분한 [평판] (https://stackoverflow.com/help/whats-reputation)이 있으면 [모든 게시물에 주석 달기] (https://stackoverflow.com/help/privileges/comment) 할 수 있습니다. 대신, [질문자의 설명이 필요없는 답변을 제공하십시오] (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do- 대신). - [리뷰에서] (리뷰/저품절 포스트/16968281) – Milap

관련 문제