2015-10-02 29 views
10

Apple hiện yêu cầu ứng dụng iOS 9 phải tuân thủ IPv6. Chúng tôi chủ yếu là OK, ngoại trừ một chút mã gửi một phát sóng UDP - điều này hiện không thành công trong iOS 9.Cần mã IPv6 Multicast C hoạt động trên iOS 9

Mọi thứ tôi đọc đều cho biết rằng đa phương tiện UDP là cách đúng để thực hiện điều này trong IPv6. Tôi đã tìm thấy một số mã ví dụ, nhưng nó không hoạt động trên bất kỳ phiên bản iOS hoặc Mac OS X mà tôi đã thử.

Mã này đang được gọi từ một C/C++ lib bên trong chương trình của chúng tôi - khó thực hiện gọi lại vào Swift, Obj-C, Java, v.v. Và mã này sẽ được chia sẻ bởi phiên bản Mac OS X và Android ứng dụng của chúng tôi. Người ta sẽ nghĩ rằng nó có thể làm IPv6 multicast trong C trong bất kỳ môi trường POSIX!

Trong ví dụ dưới đây, việc thực thi thành công với lệnh sendto() cuối cùng, thực sự gửi thông điệp UDP. Đó sendto() không thành công, với errno thiết lập để EBROKENPIPE (22) sau khi thất bại.

Dự đoán tốt nhất của tôi là tôi thiếu một số yêu cầu setsockopt() yêu cầu hoặc đang sử dụng địa chỉ phát đa hướng sai. Ngay bây giờ, tôi đang bối rối.

Dưới đây là lời gọi hàm Tôi đang làm (để multicast "Có ai ra khỏi đó?" Trên cổng UDP 4031):

char *msg = "Is anybody out there?"; 
err = multicast_udp_msg ("FF01::1111", 4031, msg, strlen(msg)); 

Dưới đây là đoạn code mà đã được gọi là:

// 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; 
} 

Suy nghĩ chào đón!

-Tim

+2

Một điều cần suy nghĩ là IPv6 multicast sử dụng cờ, phạm vi và phạm vi mà bạn thực sự cần để có được quyền. Ví dụ, phạm vi 'FF01 ::/112' là một phạm vi nút-cục bộ, nhưng tôi đoán bạn thực sự đang tìm kiếm một phạm vi liên kết cục bộ như' FF02 ::/112'. –

+0

Tôi đã thử FF02 :: 1 và FF02: 1111. Cùng một kết quả: sendto() trả về -1, errno đặt thành 22 (EBROKENPIPE). Cả hai chúng tôi đều đoán ở đây. Có ai khác thực hiện phát đa hướng trên iOS 9 không? –

+0

Tất cả những gì tôi nói là bạn cần phải cẩn thận về địa chỉ multicast bạn chọn. Tôi không biết rằng phạm vi liên kết địa phương là chính xác cho những gì bạn đang cố gắng làm (phạm vi đó sẽ không rời khỏi liên kết, như phạm vi nút-cục bộ sẽ không rời khỏi nút). Nếu bạn nhìn, FF02 :: 1 là địa chỉ All Nodes. Bạn cần phải có IPv6 được cấu hình trên máy chủ và mạng nơi bạn đang cố gắng kiểm tra điều này (có thể ping qua địa chỉ unicast IPv6).Sau đó, bạn cần phải nghiên cứu các RFC đa hướng IPv6 để tạo một nhóm lựa chọn thông minh hơn là việc nhấn-hoặc-bỏ lỡ mà bạn dường như đang cố gắng. –

Trả lời

6

Sau một số trở lại và ra với Apple và một số ngữ cảnh bổ sung, chúng tôi có câu trả lời. Nhưng đó không phải là câu trả lời cho câu hỏi ban đầu của tôi. Thứ nhất, đây là thread Apple cho bối cảnh:

https://forums.developer.apple.com/message/71107

Nó chỉ ra rằng IPv6 multicast là không thực sự những gì chúng tôi cần để giải quyết vấn đề thực sự trong tầm tay - cụ thể là, việc tìm kiếm một di sản thiết bị nhúng vào một Wi- địa phương Mạng Fi. Chúng tôi thực sự phải sử dụng phát sóng UDP IPv4 để thực hiện điều đó. Thiết bị nhúng của chúng tôi bỏ qua các gói phát đa hướng IPv6 như trái đất bỏ qua các neutrino bay qua nó.

Apple đã cho chúng tôi một cuộc gọi setockopt() đã bật phát sóng UDP IPv4 hoạt động trong iOS 9 trên mạng Wi-Fi cơ sở hạ tầng. Đó là trường hợp sử dụng dự định cho tính năng này. Và Apple cũng đã cho chúng ta một nguyên nhân gây ra sự thất bại khi phát sóng đó không hoạt động trong mạng Wi-Fi Ad Hoc (có vẻ là một vấn đề iOS 9 đã biết).

Vì vậy, mặc dù câu hỏi ban đầu của tôi không được trả lời ở đây, vấn đề cơ bản đã được giải quyết.

Các vấn đề liên quan