CFSocketでIPv6マルチキャスト受信
CF系APIを使ってIPv6マルチキャストUDPパケットを受信するサンプルです。 エラー処理等かなりいい加減なのでご注意下さい。 説明文をそのうち書くかも知れませんが、今は面倒なのでコードを解読して下さい。
サンプルコード
このサンプルのポイントは、CFSocketCreate()をPF_INET6で作成しているところと、IPV6_JOIN_GROUPを利用してマルチキャストグループに参加しているところです。
IPv4のIP_ADD_MEMBERSHIPの受信インターフェース指定はネットワークインターフェースについているIPv4アドレスを利用して設定を行いますが、IPv6のIPV6_JOIN_GROUPはネットワークインターフェース番号を利用して設定を行うという違いがあるのでご注意下さい。 ネットワークインターフェース番号は、if_nametoindex()を利用して取得できます。
#import <Cocoa/Cocoa.h>
#import <netinet/in.h>
#import <sys/socket.h>
#import <arpa/inet.h>
#import <errno.h>
NSAutoreleasePool *pool = NULL;
void
myCallbackFunc(CFSocketRef socket, CFSocketCallBackType type,
CFDataRef addr, const void *pData, void *pInfo) {
if (type != kCFSocketDataCallBack) {
NSLog(@"invalid type : %dn", type);
return;
}
NSLog(@"len=%d, [%s]",
CFDataGetLength((CFDataRef)pData),
CFDataGetBytePtr((CFDataRef)pData));
CFRunLoopStop(CFRunLoopGetCurrent());
return;
}
void
showerror_and_release_pool()
{
NSError *nserr;
nserr = [NSError errorWithDomain:NSPOSIXErrorDomain
code:errno
userInfo:NULL];
NSLog(@"%@", [nserr localizedDescription]);
[pool release];
}
int
main()
{
CFSocketRef sock;
NSError *nserr;
pool = [[NSAutoreleasePool alloc] init];
sock = CFSocketCreate(kCFAllocatorDefault, PF_INET6, SOCK_DGRAM,
IPPROTO_UDP,
kCFSocketDataCallBack,
(CFSocketCallBack)myCallbackFunc, NULL);
if (sock == NULL) {
showerror_and_release_pool();
return 1;
}
struct sockaddr_in6 myaddr;
memset(&myaddr, 0, sizeof(myaddr));
myaddr.sin6_len = sizeof(myaddr);
myaddr.sin6_family = AF_INET6;
myaddr.sin6_port = htons(10000);
myaddr.sin6_addr = in6addr_any;
CFDataRef myaddrData = CFDataCreate(NULL,
(unsigned char *)&myaddr, sizeof(myaddr));
CFSocketError serr;
serr = CFSocketSetAddress(sock, myaddrData);
if (serr != kCFSocketSuccess) {
showerror_and_release_pool();
return 1;
}
struct ipv6_mreq mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.ipv6mr_interface = if_nametoindex("en0"); /* change here */
inet_pton(AF_INET6,
"ff12::1111:cafe", &mreq.ipv6mr_multiaddr); /* change here */
if (setsockopt(CFSocketGetNative(sock),
IPPROTO_IPV6,
IPV6_JOIN_GROUP,
(char *)&mreq, sizeof(mreq)) != 0) {
showerror_and_release_pool();
return 1;
}
CFRunLoopSourceRef src;
src = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sock, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), src, kCFRunLoopCommonModes);
CFRunLoopRun();
CFRelease(src);
CFRelease(myaddrData);
CFRelease(sock);
[pool release];
return 0;
}