Commits

viv...@caravagio  committed 5ca129e

mo

  • Participants
  • Parent commits eb4267a

Comments (0)

Files changed (3)

File lib/core_unix.ml

   = "unix_mcast_join"
 ;;
 
+external mcast_join_source :
+  ?ifname : string -> File_descr.t -> Unix.sockaddr -> string -> unit
+  = "unix_mcast_join_source"
+;;
+
 external mcast_leave :
   ?ifname : string -> File_descr.t -> Unix.sockaddr -> unit
   = "unix_mcast_leave"

File lib/core_unix.mli

 *)
 val mcast_join : ?ifname : string -> File_descr.t -> sockaddr -> unit
 
+(** [mcast_join_source ?ifname sock addr source_addr] join a multicast group at [addr]
+    with socket [sock] from source at [source_addr], optionally using network interface [ifname].
+
+    @param ifname default = any interface
+*)
+val mcast_join_source : ?ifname : string -> File_descr.t -> sockaddr -> string -> unit
+
 (** [mcast_leave ?ifname sock addr] leaves a multicast group at [addr]
     with socket [sock], optionally using network interface [ifname].
 

File lib/unix_stubs.c

 MK_MCAST(join, ADD)
 MK_MCAST(leave, DROP)
 
+#define MK_MCAST1(NAME, OP) \
+  CAMLprim value unix_mcast_##NAME(value v_ifname_opt, value v_fd, value v_sa, value source_addr) \
+  { \
+    int ret, fd = Int_val(v_fd); \
+    union sock_addr_union sau; \
+    struct sockaddr *sa = &sau.s_gen; \
+    socklen_param_type sa_len; \
+    get_sockaddr(v_sa, &sau, &sa_len); \
+    struct ip_mreq_source mreq;					\
+    char* string_source_addr = String_val(source_addr);		\
+    mreq.imr_sourceaddr.s_addr = inet_addr(string_source_addr);	\
+    switch (sa->sa_family) { \
+      case AF_INET: { \
+        struct ifreq ifreq; \
+        memcpy(&mreq.imr_multiaddr, \
+               &((struct sockaddr_in *) sa)->sin_addr, \
+               sizeof(struct in_addr)); \
+        if (v_ifname_opt != Val_int(0)) { \
+          value v_ifname = Field(v_ifname_opt, 0); \
+          char *ifname = String_val(v_ifname); \
+          int ifname_len = caml_string_length(v_ifname) + 1; \
+          if (ifname_len > IFNAMSIZ) \
+            caml_failwith("mcast_" STR(NAME) ": ifname string too long"); \
+          strncpy(ifreq.ifr_name, ifname, IFNAMSIZ); \
+          if (ioctl(fd, SIOCGIFADDR, &ifreq) < 0) \
+            uerror("mcast_" STR(NAME), Nothing); \
+          memcpy(&mreq.imr_interface, \
+                 &((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr, \
+                 sizeof(struct in_addr)); \
+        } else mreq.imr_interface.s_addr = htonl(INADDR_ANY); \
+        ret = \
+          setsockopt(fd, IPPROTO_IP, IP_##OP##_MEMBERSHIP, \
+                     (char *)&mreq, sizeof(mreq)); \
+        if (ret == -1) uerror("mcast_" STR(NAME), Nothing); \
+        return Val_unit; \
+      } \
+      default : \
+        errno = EPROTONOSUPPORT; \
+        uerror("mcast_" STR(NAME), Nothing); \
+    } \
+  }
+
+MK_MCAST1(join_source, ADD_SOURCE)
+
+
 /* Similar to it's use in linux_ext, these are unfortunately not exported presently. It seems we
    should either get the functions exported, or have all portable ip level options (such as
    IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_TTL, IP_MULTICAST_LOOP, and