つまり、2つのIPアドレスとポート番号が同じであるかどうかを確認するときに、どのフィールドstruct sockaddr
を比較する必要がありますか?struct sockaddr
そして、どうsockaddr_in
ですか?
にキャストsockaddr_in
しsockaddr
て、実際のと比較できますsockaddr
か?
まず、ファミリ(IPv4、IPv6、またはその他)を確認する必要があります。次に、各sockaddrをsockaddr_inのような適切な「派生」タイプにキャストできます。Appleがそれをどのように行っているかをここでご覧ください:http ://www.opensource.apple.com/source/postfix/postfix-197/postfix/src/util/sock_addr.c
まず、値を処理するときは、を使用する必要がありますstruct sockaddr_storage
。これstruct sockaddr
は、ポインタに対してのみ安全であるためです。そうしないと、サイズと配置の問題が発生します。
第二にstruct sockaddr
、「基本クラス」のCで渡されるものです。最初のメンバーはsa_family_t sa_family;
(ただし、これstruct
は構造体メンバーが別々の名前空間にあるよりも前のものであるため、各「サブクラス」は一意のプレフィックスを使用します(少なくとも40のサブクラスに遭遇しました))。
第三に、各定義は信頼できると思うかもしれませんがstruct
、クラスのサイズはカーネル/ライブラリのバージョンによって異なることがわかります。したがって、ゴミを避けるために、常にsizeof()
実際を渡す必要があります。struct sockaddr_FOO
たとえば、の古いバージョンにはメンバーstruct sockaddr_in6
がありませんでしたsin6_scope_id
。
struct
おそらくこれを正気のためにラップする必要があります(そしてさまざまなヘルパー関数を提供します):
struct SocketAddress
{
struct sockaddr_storage addr;
socklen_t addr_len;
};
次に、比較コードは次のようになります。
// returns < 0 if (left < right)
// returns > 0 if (left > right)
// returns 0 if (left == right)
// Note that in general, "less" and "greater" are not particularly
// meaningful, but this does provide a strict weak ordering since
// you probably need one.
int socket_cmp(struct SocketAddress *left, struct SocketAddress *right)
{
socklen_t min_addr_len = left->addr_len < right->addr_len ? left->addr_len : right->addr_len;
// If head matches, longer is greater.
int default_rv = right->addr_len - left->addr_len;
int rv = memcmp(left, right, min_addr_len);
return rv ? rv : default_rv;
}
ちょっと待って!注意すれば上記のコードで十分ですが、注意することには多くの詳細が伴います。例えば:
すべてのソケットアドレスは、プログラムの1回の実行で生成されますか、それとも一部のソケットアドレスは外部メディアから読み取られますか?後者の場合、のようなケースを正規化する必要がありsin6_scope_id
ます。
ffff::1.2.3.4
同じプログラムでIPv4アドレスとIPv4-on-IPv6アドレス(のようにマップされている)の両方を処理する必要がありますか?関連する機能はIPv4アドレスも受け入れるため、最も簡単な方法は、プログラムでIPv6のみを処理することです。最高の移植性のために、フラグを無効にする(使用するsetsockopt
)ようにしてください。IPV6_V6ONLY
または、そのフラグを有効にして、IPv6アドレスにIPv4アドレスが含まれないようにすることもできます。localhost
(のルックアップは異なることに注意してください。ただし、これはすべてのドメインルックアップの一般的な問題であり、複数の結果が返される場合があります)。
すべての構造体パディングがゼロになっていることを確認する必要があります。