Appleは現在、iOS 9アプリをIPv6に準拠させる必要があります。 UDPブロードキャストを送信するコードを除いてほとんどOKですが、これはiOS 9で失敗します。iOS 9で動作するIPv6マルチキャストCコードが必要です
IPv6でこれを行うには、UDPマルチキャストが正しい方法です。私はいくつかのサンプルコードを見つけましたが、私が試したiOSまたはMac OS Xのどのバージョンでも動作しません。
このコードはSwift、Obj-C、Javaなどのコールバックを作成するのが難しいプログラム内のC/C++ライブラリから呼び出されています。このコードはMac OS XおよびAndroidバージョンの私たちのアプリ。 POSIX環境でCでIPv6マルチキャストを行うことは可能でしょうか?
以下のサンプルでは、実際にUDPメッセージを送信する最後のsendto()呼び出しまで実行が成功します。そのsendto()は失敗し、失敗後にerrnoはEBROKENPIPE(22)に設定されます。
私はいくつかの必要なsetsockopt()コールが不足しているか、間違ったマルチキャストアドレスを使用していると思います。今、私は困惑しています。ここで
は、関数呼び出し、私が作ってるんだ(マルチキャストには、「そこに誰か」UDPポート4031上で)です:
// Multicasts a message on a specific UDP port.
// myhost - IPv6 address on which to multicast the message (i.e., ourself)
// port - UDP port on which to broadcast the mssage
// msg - message contents to broadcast
// msgsize - length of message in bytes
// Return value is zero if successful, or nonzero on error.
int multicast_udp_msg (char *myhost, short port, char *msg, size_t msgsize)
{
int sockfd, n;
char service[16] = { 0 };
int err = 0;
struct addrinfo hints = { 0 }, *res, *ressave;
struct sockaddr_storage addr = { 0 };
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
sprintf (service, "%hd", port);
n = getaddrinfo (myhost, service, &hints, &res);
if (n < 0)
{
fprintf(stderr, "getaddrinfo error:: [%s]\n", gai_strerror(n));
return -1;
}
ressave = res;
sockfd = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd >= 0)
{
memcpy (&addr, res->ai_addr, sizeof (addr));
if (joinGroup (sockfd, 0, 8, &addr) == 0)
if (bind (sockfd, res->ai_addr, res->ai_addrlen) == 0)
if (sendto (sockfd, msg, msgsize, 0, (struct sockaddr *) &addr, sizeof (addr)) < 0)
err = errno;
close (sockfd);
res = res->ai_next;
}
freeaddrinfo (ressave);
return err;
}
int
joinGroup(int sockfd, int loopBack, int mcastTTL,
struct sockaddr_storage *addr)
{
int r1, r2, r3, retval;
retval=-1;
switch (addr->ss_family) {
case AF_INET: {
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr=
((struct sockaddr_in *)addr)->sin_addr.s_addr;
mreq.imr_interface.s_addr= INADDR_ANY;
r1= setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
&loopBack, sizeof(loopBack));
if (r1<0)
perror("joinGroup:: IP_MULTICAST_LOOP:: ");
r2= setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
&mcastTTL, sizeof(mcastTTL));
if (r2<0)
perror("joinGroup:: IP_MULTICAST_TTL:: ");
r3= setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const void *)&mreq, sizeof(mreq));
if (r3<0)
perror("joinGroup:: IP_ADD_MEMBERSHIP:: ");
} break;
case AF_INET6: {
struct ipv6_mreq mreq6;
memcpy(&mreq6.ipv6mr_multiaddr,
&(((struct sockaddr_in6 *)addr)->sin6_addr),
sizeof(struct in6_addr));
mreq6.ipv6mr_interface= 0; // cualquier interfaz
r1= setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
&loopBack, sizeof(loopBack));
if (r1<0)
perror("joinGroup:: IPV6_MULTICAST_LOOP:: ");
r2= setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
&mcastTTL, sizeof(mcastTTL));
if (r2<0)
perror("joinGroup:: IPV6_MULTICAST_HOPS:: ");
r3= setsockopt(sockfd, IPPROTO_IPV6,
IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6));
if (r3<0)
perror("joinGroup:: IPV6_ADD_MEMBERSHIP:: ");
} break;
default:
r1=r2=r3=-1;
}
if ((r1>=0) && (r2>=0) && (r3>=0))
retval=0;
return retval;
}
:
char *msg = "Is anybody out there?";
err = multicast_udp_msg ("FF01::1111", 4031, msg, strlen(msg));
ここで呼び出されているコードです思考は歓迎! Appleといくつかの前後、およびいくつかの追加のコンテキストの後
IPv6マルチキャストは、本当に必要なフラグ、スコープ、範囲を使用するということを考えてください。例えば、 'FF01 ::/112'はノードローカルスコープですが、' FF02 ::/112'のようなリンクローカルスコープを本当に探していると思います。 –
私はFF02 :: 1とFF02:1111を試しました。同じ結果:sendto()は-1を返し、errnoは22(EBROKENPIPE)に設定します。私たちはどちらもここで推測しています。他の誰かがiOS 9でマルチキャストを実装していますか? –
私が言っていたのは、あなたが選んだマルチキャストアドレスに注意する必要があるということでした。私は、リンクローカルスコープがあなたがやっていることが正しいことを知らない(そのスコープはリンクを離れず、ノードローカルスコープがノードを離れることはない)。あなたが見た場合、FF02 :: 1はAll Nodesアドレスです。これをテストしようとしているホストやネットワーク上でIPv6を設定する必要があります(IPv6ユニキャストアドレス経由でpingできるようにする必要があります)。次に、IPv6マルチキャストRFCを研究して、あなたが試みているようなヒットミスではなくインテリジェントなグループ選択を行う必要があります。 –