2017-12-16 11 views
0

커맨드 라인에서 제공되는 UDP 소켓 프로그램을 작성하고 있습니다.Sockaddr union과 getaddrinfo()

보내기 및 쓰기가 쉬워 지도록 getaddrinfo를 사용하여 주소를 sockaddr 구조체 (sockaddr_in 또는 sockaddr_in6)로 변환합니다. 지금은 내가 sockaddrs의 조합을 사용한다는 것을 이해 :

typedef union address 
{ 
    struct sockaddr s; 
    struct sockaddr_in s4; 
    struct sockaddr_in6 s6; 
    struct sockaddr_storage ss; 
} address_t; 

나는 그들이 엄격한 앨리어싱 문제를 숨기고 피하기 위해 포인터가 될 수 없습니다 알고있는 것처럼. 나는 원활이는 Address_t로한다 getaddrinfo의되는 addrinfo의 정보를 넣어하는 데 문제 :

struct addrinfo hint, *serv = NULL; 
address_t addr; 

hint.ai_family = AF_UNSPEC; 
hint.ai_flags = 0; 
hint.ai_socktype = SOCK_DGRAM; 
hint.ai_protocol = IPPROTO_UDP; 

ret = getaddrinfo(address_sr.c_str(), s_port.c_str(), &hint, &serv); 
//address_sr and s_port are strings with the address and port 

switch (serv->ai_addr) { 
    case AF_INET: { 
     addr->s4 = * (sockaddr_in*) serv->ai_addr; 
     //Here I want to fill the address_t struct with information 
     //This line causes a segfault 
    } 
    break; 
    case AF_INET6: { 
     addr->s6 = * (sockaddr_in6*) serv->ai_addr; 
     //Conversion here 
    } 
    break; 

을 또한, 메모리 복사 :

memcpy(&addr, serv->ai_addr, serv->ai_addrlen); 

너무 segfault의 원인.

정확히 어떻게해야합니까? 나는 12 가지의 다른 방법을 시도했고, 나는 그것을 알아낼 수 없다. addrinfo의 주소를이 공용체에 넣으려면 어떻게해야합니까? sockaddr_storage 또는 sockaddr_ins를 사용합니까?

편집 : 명확성 및 추가 코드 정보를 위해 편집.

+0

일부'방어 적이기()'작업을 대신 할당 : 그래서, 예를 들어, 단지 memcpy() 전체 serv->ai_addr 하나의 작업에서와와 switch 제거? – user0042

+0

일부 오류 검사를하는 것이 도움이 될 수 있습니다. serv가 null 인 경우 어떻게됩니까? –

답변

1

포인터를 참조 해제해야합니다.

addr->s4 = *(sockaddr_in*) serv->ai_addr; 
+0

시작시 이전에는 분명히 없었던 segfault를 반환합니다. –

1

나는 getaddrinfo이 맞지 않다고 생각합니다. 세 번째 인수에 대해

: 고해상도 가리키는 목록에 반환 된 소켓 주소 구조를 선택하는 조건을 지정하는되는 addrinfo 구조

const struct addrinfo *hints 

힌트 인수를 가리 킵니다. 힌트가 NULL이 아닌 경우 당신은, 예를 들어

[...]를 ai_family, ai_socktype를, 그리고 ai_protocol 한다 getaddrinfo (에 의해 반환 된 소켓 주소)의 집합을 제한 기준을 지정한되는 addrinfo 구조를 가리키는 IPv4 주소 패밀리 및/또는 데이터 그램 소켓에 대해서만 요청할 수 있습니다 (UDP를 사용하려는 경우 문제가 될 수 있음). 는 기본적으로, 당신이되는 addrinfo 인스턴스를 제공, 관심 분야를 설정 한 다음 세 번째 인수로 함수에 대한 포인터를 전달합니다

struct addrinfo hints; 
memset(&hints, 0, sizeof(struct addrinfo)); 
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ 
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ 

ret = getaddrinfo(address_sr.c_str(), s_port.c_str(), &hint, &serv); 

이 예제에서, 함수는 단지 하나를 반환 할 수도 있지만 어드레스 구조의 전체 목록 :

한다 getaddrinfo() 함수가 할당 힌트에 의해 부과 된 제한 사항이 적용 되는 addrinfo 구조 노드 서비스 일치하는 각 네트워크 주소에 대한 하나의 링크리스트를 초기화하고, 은 l의 시작 부분에 대한 포인터입니다. 입술에 ist. 연결된 목록의 항목은 ai_next 필드로 연결됩니다.

for (rp = serv; rp != NULL; rp = rp->ai_next) 

난 강력하게주의 깊게 내가 제공된 링크에서 설명서를 참조하는 것이 좋습니다 :

그래서 당신은 함수 결과를 통해 루프에이 방법이있다. 또한 문제를 해결할 수있는 길고 구체적인 예가 있습니다.

+0

getaddrinfo가 작동하는 방식과 반환 방식을 이해합니다. 나는 addressrin_t를 addrinfo의 첫 번째 대답으로 올바르게 채우는 방법을 구체적으로 묻고있다. 네트워크 프로그래밍에 관한 모든 Beejs 가이드와 12 개의 다른 게시물을 읽었으며 일부는 노조에 대해서는 언급하지 않았지만 명시 적 예제는 제공하지 않았습니다. 지금까지 [this] (https://stackoverflow.com/questions/47846444/sockaddr-union-and-getaddrinfo/47846998#47846998) 및 [that] (https://stackoverflow.com/questions/47846444/sockaddr-union) -and-getaddrinfo/47846998 # 47846998) 대답은 segfaults를 제공하므로 작동하지 않습니다. –

+0

왜 내가 그 노동 조합을 사용해야하는지 이해가 안됩니다. beejs 예제에서도 getaddrinfo가 반환 한 구조는 socket/connect/bind에서 직접 사용되며 freeaddrinfo는 바로 뒤에 호출됩니다. sockaddr 구조체를 복사하여 붙여 넣을 이유가 없습니다. –

+0

나는 UDP 서버와 클라이언트 프로그램을 가지고 있기 때문에 서버는 정보를 끊임없이 보내는 여러 클라이언트를 가지고있다. 내가 싱글 렛 방식으로하고 있기 때문에 내가받는 것보다 더 많은 패킷을 보내기 때문에 정보를 저장해야한다. 따라서 주소를 저장할 필요가 있습니다. 나는 또한 그것이 Beejs 가이드에서 눈부신 생략이라고 생각합니다. sockaddr_storage를 사용하는 것의 한 가지 적절한 예는 아닙니다. –

0

sockaddr_storage 따라서 address_t 그냥 큰 만들기, 어떤sockaddr_... 유형을 저장하기에 충분히 크다. 어쩌면

struct addrinfo hints = {}; 
struct addrinfo *addrs, *serv; 
address_t addr; 

hints.ai_family = AF_UNSPEC; 
hints.ai_socktype = SOCK_DGRAM; 
... 

ret = getaddrinfo(address_sr.c_str(), s_port.c_str(), &hint, &addrs); 
if (ret == 0) 
{ 
    for (serv = addrs; serv != NULL; serv = serv->ai_next) 
    { 
     memcpy(&addr, serv->ai_addr, serv->ai_addrlen); 
     ... 
    } 
    freeaddrinfo(addrs); 
} 
+0

이것은 슬프게도 버퍼 오버 플로우를 일으킨다. –

+0

@m_highlanderish이 코드에는'sizeof (address_t) == sizeof (sockaddr_storage)'와'serv-> ai_addrlen'은 항상'<= sizeof (sockaddr_storage)'로 버퍼 오버 플로우가 없다. –