Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/develop d11c52fca -> a2c715065


mn_socket/native; multicast support.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/a2c71506
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/a2c71506
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/a2c71506

Branch: refs/heads/develop
Commit: a2c71506504abf8f05e3730ba69f4024432cd6dd
Parents: d11c52f
Author: Marko Kiiskila <ma...@runtime.io>
Authored: Fri Sep 16 10:45:42 2016 -0700
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Fri Sep 16 10:45:42 2016 -0700

----------------------------------------------------------------------
 sys/mn_socket/include/mn_socket/mn_socket.h   |  24 +++-
 sys/mn_socket/src/arch/sim/native_itf.c       |  30 +++++
 sys/mn_socket/src/arch/sim/native_sock.c      |  87 ++++++++++++-
 sys/mn_socket/src/arch/sim/native_sock_priv.h |   1 +
 sys/mn_socket/src/test/mn_sock_test.c         | 136 +++++++++++++++++++++
 5 files changed, 274 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/a2c71506/sys/mn_socket/include/mn_socket/mn_socket.h
----------------------------------------------------------------------
diff --git a/sys/mn_socket/include/mn_socket/mn_socket.h 
b/sys/mn_socket/include/mn_socket/mn_socket.h
index bcbe34f..17ee35f 100644
--- a/sys/mn_socket/include/mn_socket/mn_socket.h
+++ b/sys/mn_socket/include/mn_socket/mn_socket.h
@@ -49,16 +49,16 @@
 #define MN_ETIMEDOUT            9
 #define MN_EAGAIN               10
 #define MN_EUNKNOWN             11
+#define MN_EADDRNOTAVAIL        12
 
 /*
  * Multicast macros
  */
 #define MN_IN_MULTICAST(a)                                              \
-    (((a) & 0xf0000000) == 0xe0000000)
+    ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
 
-/* XXXX notyet */
 #define MN_IN6_IS_ADDR_MULTICAST(a)                                     \
-    0
+    ((a)->s_addr[0] == 0xff)
 
 struct mn_socket;
 struct mn_socket_ops;
@@ -118,6 +118,24 @@ struct mn_sockaddr_in6 {
 extern const uint32_t nm_in6addr_any[4];
 
 /*
+ * Structure for multicast join/leave
+ */
+struct mn_mreq {
+    uint8_t mm_idx;                    /* interface index */
+    uint8_t mm_family;                 /* address family */
+    union {
+        struct mn_in_addr v4;
+        struct mn_in6_addr v6;
+    } mm_addr;
+};
+
+#define MN_SO_LEVEL                     0xfe
+
+#define MN_MCAST_JOIN_GROUP             1
+#define MN_MCAST_LEAVE_GROUP            2
+#define MN_MCAST_IF                     3
+
+/*
  * Socket calls.
  *
  * mn_connect() for TCP is asynchronous. Once connection has been established,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/a2c71506/sys/mn_socket/src/arch/sim/native_itf.c
----------------------------------------------------------------------
diff --git a/sys/mn_socket/src/arch/sim/native_itf.c 
b/sys/mn_socket/src/arch/sim/native_itf.c
index 09318b3..8f22f49 100644
--- a/sys/mn_socket/src/arch/sim/native_itf.c
+++ b/sys/mn_socket/src/arch/sim/native_itf.c
@@ -106,6 +106,36 @@ plen(void *addr, int alen)
 }
 
 int
+native_sock_itf_addr(int idx, uint32_t *addr)
+{
+    struct ifaddrs *ifap;
+    struct ifaddrs *ifa;
+    struct sockaddr_in *sin;
+    int rc;
+
+    rc = getifaddrs(&ifap);
+    if (rc < 0) {
+        rc = native_sock_err_to_mn_err(errno);
+        return rc;
+    }
+
+    rc = MN_EADDRNOTAVAIL;
+    for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+        if (if_nametoindex(ifa->ifa_name) != idx) {
+            continue;
+        }
+        if (ifa->ifa_addr->sa_family == AF_INET) {
+            sin = (struct sockaddr_in *)ifa->ifa_addr;
+            *addr = sin->sin_addr.s_addr;
+            rc = 0;
+            break;
+        }
+    }
+    freeifaddrs(ifap);
+    return rc;
+}
+
+int
 native_sock_itf_addr_getnext(struct mn_itf *mi, struct mn_itf_addr *mia)
 {
     struct ifaddrs *ifap;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/a2c71506/sys/mn_socket/src/arch/sim/native_sock.c
----------------------------------------------------------------------
diff --git a/sys/mn_socket/src/arch/sim/native_sock.c 
b/sys/mn_socket/src/arch/sim/native_sock.c
index 73ca6c7..e411f6e 100644
--- a/sys/mn_socket/src/arch/sim/native_sock.c
+++ b/sys/mn_socket/src/arch/sim/native_sock.c
@@ -51,6 +51,11 @@ static int native_sock_sendto(struct mn_socket *, struct 
os_mbuf *,
   struct mn_sockaddr *);
 static int native_sock_recvfrom(struct mn_socket *, struct os_mbuf **,
   struct mn_sockaddr *);
+static int native_sock_getsockopt(struct mn_socket *, uint8_t level,
+  uint8_t name, void *val);
+static int native_sock_setsockopt(struct mn_socket *, uint8_t level,
+  uint8_t name, void *val);
+
 static int native_sock_getsockname(struct mn_socket *, struct mn_sockaddr *);
 static int native_sock_getpeername(struct mn_socket *, struct mn_sockaddr *);
 
@@ -60,6 +65,7 @@ static struct native_sock {
     unsigned int ns_poll:1;
     unsigned int ns_listen:1;
     uint8_t ns_type;
+    uint8_t ns_pf;
     struct os_sem ns_sem;
     STAILQ_HEAD(, os_mbuf_pkthdr) ns_rx;
     struct os_mbuf *ns_tx;
@@ -83,6 +89,9 @@ static const struct mn_socket_ops native_sock_ops = {
     .mso_sendto = native_sock_sendto,
     .mso_recvfrom = native_sock_recvfrom,
 
+    .mso_getsockopt = native_sock_getsockopt,
+    .mso_setsockopt = native_sock_setsockopt,
+
     .mso_getsockname = native_sock_getsockname,
     .mso_getpeername = native_sock_getpeername,
 
@@ -154,8 +163,9 @@ native_sock_err_to_mn_err(int err)
     case ENOMEM:
         return MN_ENOBUFS;
     case EADDRINUSE:
-    case EADDRNOTAVAIL:
         return MN_EADDRINUSE;
+    case EADDRNOTAVAIL:
+        return MN_EADDRNOTAVAIL;
     default:
         return MN_EINVAL;
     }
@@ -260,6 +270,7 @@ native_sock_create(struct mn_socket **sp, uint8_t domain,
     os_sem_init(&ns->ns_sem, 0);
     idx = socket(domain, type, proto);
     ns->ns_fd = idx;
+    ns->ns_pf = domain;
     ns->ns_type = type;
     os_mutex_release(&nss->mtx);
     if (idx < 0) {
@@ -514,6 +525,80 @@ native_sock_recvfrom(struct mn_socket *s, struct os_mbuf 
**mp,
 }
 
 static int
+native_sock_getsockopt(struct mn_socket *s, uint8_t level, uint8_t name,
+  void *val)
+{
+    return MN_EPROTONOSUPPORT;
+}
+
+static int
+native_sock_setsockopt(struct mn_socket *s, uint8_t level, uint8_t name,
+  void *val)
+{
+    struct native_sock *ns = (struct native_sock *)s;
+    int rc;
+    uint32_t val32;
+    struct group_req greq;
+    struct sockaddr_in *sin;
+    struct sockaddr_in6 *sin6;
+    struct mn_mreq *mreq;
+
+    if (level == MN_SO_LEVEL) {
+        switch (name) {
+        case MN_MCAST_JOIN_GROUP:
+        case MN_MCAST_LEAVE_GROUP:
+            mreq = val;
+            memset(&greq, 0, sizeof(greq));
+            greq.gr_interface = mreq->mm_idx;
+            if (mreq->mm_family == MN_AF_INET) {
+                sin = (struct sockaddr_in *)&greq.gr_group;
+                sin->sin_len = sizeof(*sin);
+                sin->sin_family = AF_INET;
+                memcpy(&sin->sin_addr, &mreq->mm_addr, sizeof(struct in_addr));
+                level = IPPROTO_IP;
+            } else {
+                sin6 = (struct sockaddr_in6 *)&greq.gr_group;
+                sin6->sin6_len = sizeof(*sin6);
+                sin6->sin6_family = AF_INET6;
+                memcpy(&sin6->sin6_addr, &mreq->mm_addr,
+                  sizeof(struct in6_addr));
+                level = IPPROTO_IPV6;
+            }
+
+            if (name == MN_MCAST_JOIN_GROUP) {
+                name = MCAST_JOIN_GROUP;
+            } else {
+                name = MCAST_LEAVE_GROUP;
+            }
+            rc = setsockopt(ns->ns_fd, level, name, &greq, sizeof(greq));
+            if (rc) {
+                return native_sock_err_to_mn_err(errno);
+            }
+            return 0;
+        case MN_MCAST_IF:
+            if (ns->ns_pf == AF_INET) {
+                level = IPPROTO_IP;
+                name = IP_MULTICAST_IF;
+                rc = native_sock_itf_addr(*(int *)val, &val32);
+                if (rc) {
+                    return rc;
+                }
+            } else {
+                level = IPPROTO_IPV6;
+                name = IPV6_MULTICAST_IF;
+                val32 = *(uint32_t *)val;
+            }
+            rc = setsockopt(ns->ns_fd, level, name, &val32, sizeof(val32));
+            if (rc) {
+                return native_sock_err_to_mn_err(errno);
+            }
+            return 0;
+        }
+    }
+    return MN_EPROTONOSUPPORT;
+}
+
+static int
 native_sock_getsockname(struct mn_socket *s, struct mn_sockaddr *addr)
 {
     struct native_sock *ns = (struct native_sock *)s;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/a2c71506/sys/mn_socket/src/arch/sim/native_sock_priv.h
----------------------------------------------------------------------
diff --git a/sys/mn_socket/src/arch/sim/native_sock_priv.h 
b/sys/mn_socket/src/arch/sim/native_sock_priv.h
index aec3809..108cbeb 100644
--- a/sys/mn_socket/src/arch/sim/native_sock_priv.h
+++ b/sys/mn_socket/src/arch/sim/native_sock_priv.h
@@ -25,6 +25,7 @@ struct mn_itf_addr;
 
 int native_sock_itf_getnext(struct mn_itf *);
 int native_sock_itf_addr_getnext(struct mn_itf *, struct mn_itf_addr *);
+int native_sock_itf_addr(int idx, uint32_t *addr);
 
 int native_sock_err_to_mn_err(int err);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/a2c71506/sys/mn_socket/src/test/mn_sock_test.c
----------------------------------------------------------------------
diff --git a/sys/mn_socket/src/test/mn_sock_test.c 
b/sys/mn_socket/src/test/mn_sock_test.c
index a0f85da..1d68f7b 100644
--- a/sys/mn_socket/src/test/mn_sock_test.c
+++ b/sys/mn_socket/src/test/mn_sock_test.c
@@ -600,6 +600,141 @@ sock_udp_ll(void)
     mn_close(sock2);
 }
 
+static int
+sock_find_loopback_if(void)
+{
+    struct mn_itf itf;
+    struct mn_itf_addr itf_addr;
+    struct mn_in_addr addr127;
+
+    mn_inet_pton(MN_PF_INET, "127.0.0.1", &addr127);
+
+    memset(&itf, 0, sizeof(itf));
+
+    while (1) {
+        if (mn_itf_getnext(&itf)) {
+            break;
+        }
+        memset(&itf_addr, 0, sizeof(itf_addr));
+        while (1) {
+            if (mn_itf_addr_getnext(&itf, &itf_addr)) {
+                break;
+            }
+            if (itf_addr.mifa_family == MN_AF_INET &&
+              !memcmp(&itf_addr.mifa_addr, &addr127, sizeof(addr127))) {
+                return itf.mif_idx;
+            }
+        }
+    }
+    return -1;
+}
+
+void
+sum4_readable(void *cb_arg, int err)
+{
+    os_sem_release(&test_sem);
+}
+
+static void
+sock_udp_mcast_v4(void)
+{
+    int loop_if_idx;
+    struct mn_socket *rx_sock;
+    struct mn_socket *tx_sock;
+    struct mn_sockaddr_in msin;
+    union mn_socket_cb sock_cbs = {
+        .socket.readable = sum4_readable
+    };
+    struct os_mbuf *m;
+    char data[] = "1234567890";
+    int rc;
+    struct mn_mreq mreq;
+    loop_if_idx = sock_find_loopback_if();
+    TEST_ASSERT(loop_if_idx > 0);
+
+    msin.msin_family = MN_AF_INET;
+    msin.msin_len = sizeof(msin);
+    msin.msin_port = htons(44344);
+    memset(&msin.msin_addr, 0, sizeof(msin.msin_addr));
+
+    rc = mn_socket(&rx_sock, MN_PF_INET, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+    mn_socket_set_cbs(rx_sock, NULL, &sock_cbs);
+
+    rc = mn_bind(rx_sock, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_socket(&tx_sock, MN_PF_INET, MN_SOCK_DGRAM, 0);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_setsockopt(tx_sock, MN_SO_LEVEL, MN_MCAST_IF, &loop_if_idx);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * multicast tgt
+     */
+    mn_inet_pton(MN_PF_INET, "224.0.2.241", &msin.msin_addr);
+
+    rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * RX socket has not joined group yet.
+     */
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC / 2);
+    TEST_ASSERT(rc == OS_TIMEOUT);
+
+    mreq.mm_idx = loop_if_idx;
+    mreq.mm_family = MN_AF_INET;
+    mreq.mm_addr.v4.s_addr = msin.msin_addr.s_addr;
+
+    /*
+     * Now join it.
+     */
+    rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_JOIN_GROUP, &mreq);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_recvfrom(rx_sock, &m, NULL);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(m != NULL);
+    TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data)));
+    os_mbuf_free_chain(m);
+
+    /*
+     * Then leave
+     */
+    rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_LEAVE_GROUP, &mreq);
+    TEST_ASSERT(rc == 0);
+
+    m = os_msys_get(sizeof(data), 0);
+    TEST_ASSERT(m);
+    rc = os_mbuf_copyinto(m, 0, data, sizeof(data));
+    TEST_ASSERT(rc == 0);
+
+    rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin);
+    TEST_ASSERT(rc == 0);
+
+    rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC);
+    TEST_ASSERT(rc == OS_TIMEOUT);
+
+    mn_close(rx_sock);
+    mn_close(tx_sock);
+}
+
 void
 mn_socket_test_handler(void *arg)
 {
@@ -610,6 +745,7 @@ mn_socket_test_handler(void *arg)
     sock_tcp_data();
     sock_itf_list();
     sock_udp_ll();
+    sock_udp_mcast_v4();
     os_test_restart();
 }
 

Reply via email to