CFSocketでIPv6マルチキャスト送信

CF系APIを使ってIPv6マルチキャストUDPパケットを送信するサンプルです。 エラー処理等かなりいい加減なのでご注意下さい。 説明文をそのうち書くかも知れませんが、今は面倒なのでコードを解読して下さい。

サンプルコード

このサンプルのポイントは、CFSocketCreate()をPF_INET6で作成しているところと、IPV6_MULTICAST_IFを利用してマルチキャスト送出インターンフェースを指定しているところです。

IPv4のIP_MULTICAST_IFはネットワークインターフェースについているIPv4アドレスを利用して設定を行いますが、IPv6のIPV6_MULTICAST_IFはネットワークインターフェース番号を利用して設定を行うという違いがあるのでご注意下さい。 ネットワークインターフェース番号は、if_nametoindex()を利用して取得できます。


#import <Cocoa/Cocoa.h>
#import <netinet/in.h>
#import <sys/socket.h>
#import <errno.h>

NSAutoreleasePool *pool = NULL;

void
showerror_and_release_pool()
{
  NSError *nserr;
  nserr = [NSError errorWithDomain:NSPOSIXErrorDomain
                     code:errno
                     userInfo:NULL];

  NSLog(@"%@", [nserr localizedDescription]);

  [pool release];
}

int
main()
{
  CFSocketRef sock;
  CFSocketError err;

  pool  = [[NSAutoreleasePool alloc] init];

  sock = CFSocketCreate(kCFAllocatorDefault, PF_INET6, SOCK_DGRAM,
             IPPROTO_UDP,
             kCFSocketNoCallBack,
             NULL, NULL);  
  if (sock == NULL) {
    showerror_and_release_pool();
    return 1;
  }

  struct sockaddr_in6 dest;
  memset(&dest, 0, sizeof(dest));
  dest.sin6_len = sizeof(dest);
  dest.sin6_family = AF_INET6;
  dest.sin6_port = htons(10000);
  inet_pton(AF_INET6, "ff12::1111:cafe", &dest.sin6_addr); /* change here */

  unsigned int ifidx = if_nametoindex("en0"); /* change here */

  NSLog(@"ifindex = %d", ifidx);

  if (setsockopt(CFSocketGetNative(sock),
          IPPROTO_IPV6,
          IPV6_MULTICAST_IF,
          (char *)&ifidx, sizeof(ifidx)) != 0) {
    NSLog(@"setsockopt failed");
    showerror_and_release_pool();
    return 1;
  }

  CFDataRef destData = CFDataCreate(NULL, (unsigned char *)&dest, sizeof(dest));

  CFDataRef msgData = CFDataCreate(NULL, (unsigned char *)"HOGE", 4);

  err = CFSocketSendData(sock, destData, msgData, 4);
  if (err != kCFSocketSuccess) {
    NSLog(@"CFSocketSendData failed");
    showerror_and_release_pool();
    return 1;
  }

  [pool release];

  return 0;
}