2017-12-16 11 views
0

私はコマンドラインからのアドレスで提供されるUDPソケットプログラムを書いています。Sockaddr共用体とgetaddrinfo()

私はsendaddとwriteを簡単にするために、アドレスをsockaddr構造体(sockaddr_inまたはsockaddr_in6)に変換するためにgetaddrinfoを使用しています。私は、彼らが厳しいエイリアシングの問題を隠して回避するためにポインタをすることはできません理解したよう

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

:今、私はsockaddrsの組合を使用する必要があることを理解しています。私はシームレスにこの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); 

もセグメンテーションフォルトを引き起こします。

これをどのように正確に行う必要がありますか?私は十数通りの方法を試しましたが、私はそれを理解できません。どのようにaddrinfoからのアドレスをこの共用体に置くのですか? sockaddr_storageまたはsockaddr_insを使用しますか?

EDIT:明快さと追加のコード情報のための編集。

+0

いくつかの 'のmemcpy()'操作の代わりに、割り当て多分? – user0042

+0

おそらく、何らかのエラーチェックをすることが役に立ちます。 servがnullの場合はどうなりますか? –

答えて

1

ポインタの参照を解除する必要があります。

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

これが起動すると、前にはなかったsegfaultが返されます。 –

1

私はあなたがgetaddrinfoを正しく取得していないと思います。三番目の引数、について

const struct addrinfo *hints 

ヒント引数のresで指さ リストに返されたソケットアドレス構造体を選択するための 条件を指定addrinfo構造体へのポイント。ヒントがNULLでない場合、それは、そののai_familiy、ai_socktype、およびai_protocolは はgetaddrinfo()[...]例えば

によって返されたソケットアドレスのセットを制限 基準を指定したaddrinfo 構造体を指し、あなたIPv4アドレスファミリのみ、および/またはデータグラムソケットのみを要求することができます(UDPを使用しようとしても問題ありません)。 は基本的に、あなたはその3番目の引数として、関数にポインタを渡し、興味のある分野を設定し、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); 

この例では、機能だけではなく1を返すことができますが、アドレス構造の全体のリスト:

のgetaddrinfo()関数を割り当て、ヒントによって課される任意の制限を受ける addrinfo構造体、ノード サービス一致する各ネットワーク・アドレスのための1つのリンク・リストを初期化し、そして は、lの開始位置へのポインタを返します。 resにはist。リンクされた リストのアイテムは、ai_nextフィールドでリンクされています。

だから、関数の結果をループにこの方法があります:

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

を私は強く、慎重に私が提供されたリンクで文書を読むことをお勧めします。あなただけの問題を解決することができる長く詳細な例もあります。

+0

私はgetaddrinfoがどのように動作し、何が返されるのか理解しています。私は、addressrin_tをaddrinfoの最初の答えで正しく埋める方法を具体的に求めています。私は、Beejs Guide to Network Programmingと他の十数個の記事を読んでいますが、その中のいくつかはユニオンについて言及していますが、明示的な例はありません。これまでのところ[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_...タイプを保持するのに十分な大きさです。だから、私はちょうどmemcpy() 1回の操作で全体serv->ai_addrと例えば、switchを取り除くでしょう:

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) 'になるので、このコードではバッファオーバーフローはありません。 –