You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/07/13 18:07:48 UTC

[2/4] incubator-mynewt-core git commit: MYNEWT-314; First take on the socket interface.

MYNEWT-314; First take on the socket interface.


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/2fbc2b69
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/2fbc2b69
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/2fbc2b69

Branch: refs/heads/ble_hs_api
Commit: 2fbc2b699b92d2143cb6b152c57a93bb5bb26983
Parents: 8da07ef
Author: Marko Kiiskila <ma...@runtime.io>
Authored: Mon Jul 11 16:59:46 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Tue Jul 12 16:48:06 2016 -0700

----------------------------------------------------------------------
 sys/mn_socket/include/mn_socket/mn_socket.h     | 141 +++++++++++++++++++
 sys/mn_socket/include/mn_socket/mn_socket_ops.h |  82 +++++++++++
 sys/mn_socket/pkg.yml                           |  31 ++++
 sys/mn_socket/src/mn_socket.c                   | 123 ++++++++++++++++
 sys/mn_socket/src/mn_socket_aconv.c             |  57 ++++++++
 sys/mn_socket/src/test/mn_sock_test.c           |  82 +++++++++++
 6 files changed, 516 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2fbc2b69/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
new file mode 100644
index 0000000..75ebc8c
--- /dev/null
+++ b/sys/mn_socket/include/mn_socket/mn_socket.h
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef __SYS_MN_SOCKET_H_
+#define __SYS_MN_SOCKET_H_
+
+#include <inttypes.h>
+
+/*
+ * Address/protocol family.
+ */
+#define MN_AF_INET              4
+#define MN_PF_INET              MN_AF_INET
+#define MN_AF_INET6             6
+#define MN_PF_INET6             MN_AF_INET6
+
+/*
+ * Socket types
+ */
+#define MN_SOCK_STREAM          1
+#define MN_SOCK_DGRAM           2
+
+/*
+ * Error codes from mn_socket interface.
+ */
+#define MN_EAFNOSUPPORT         1
+#define MN_EPROTONOSUPPORT      2
+#define MN_ENOBUFS              3
+#define MN_EINVAL               4
+#define MN_ENOTCONN             5
+#define MN_ECONNABORTED         6
+#define MN_EDESTADDRREQ         7
+#define MN_EADDRINUSE           8
+#define MN_ETIMEDOUT            9
+#define MN_EAGAIN               10
+#define MN_EUNKNOWN             11
+
+struct mn_socket;
+struct mn_socket_ops;
+struct mn_sock_cb;
+struct os_mbuf;
+
+struct mn_socket {
+    const union mn_socket_cb *ms_cbs;          /* filled in by user */
+    const struct mn_socket_ops *ms_ops;        /* filled in by mn_socket */
+};
+
+/*
+ * Callbacks. Socket callbacks are for sockets which exchange
+ * data. Listen callback is for TCP listen sockets.
+ */
+union mn_socket_cb {
+    struct {
+        void (*readable)(struct mn_socket *, int err);
+        void (*writable)(struct mn_socket *, int err);
+    } socket;
+    struct {
+        int (*newconn)(struct mn_socket *listen, struct mn_socket *new);
+    } listen;
+};
+
+struct mn_sockaddr {
+    uint8_t msa_len;
+    uint8_t msa_family;
+    char    msa_data[2];
+};
+
+struct mn_sockaddr_in {
+    uint8_t msin_len;
+    uint8_t msin_family;
+    uint16_t msin_port;
+    uint32_t msin_addr;
+};
+
+struct mn_sockaddr_in6 {
+    uint8_t msin6_len;
+    uint8_t msin6_family;
+    uint16_t msin6_port;
+    uint32_t msin6_flowinfo;
+    uint32_t msin6_addr[4];
+};
+
+/*
+ * Socket calls.
+ *
+ * mn_connect() for TCP is asynchronous. Once connection has been established,
+ * socket callback (*writable) will be called.
+ *
+ * mn_sendto() is asynchronous as well. If it fails due to buffer shortage,
+ * socket provider should call (*writable) when more data can be sent.
+ *
+ * mn_recvfrom() returns immediatelly if no data is available. If data arrives,
+ * the callback (*readable) will be called. Once that happens, owner of the
+ * socket should keep calling mn_recvfrom() until it has drained all the
+ * data from the socket.
+ *
+ * If remote end closes the socket, socket callback (*readable) will be
+ * called.
+ */
+int mn_socket(struct mn_socket **, uint8_t domain, uint8_t type, uint8_t proto);
+int mn_bind(struct mn_socket *, struct mn_sockaddr *);
+int mn_connect(struct mn_socket *, struct mn_sockaddr *);
+int mn_listen(struct mn_socket *, uint8_t qlen);
+
+int mn_recvfrom(struct mn_socket *, struct os_mbuf **,
+  struct mn_sockaddr *from);
+int mn_sendto(struct mn_socket *, struct os_mbuf *, struct mn_sockaddr *to);
+
+int mn_getsockopt(struct mn_socket *, uint8_t level, uint8_t optname,
+  void *optval);
+int mn_setsockopt(struct mn_socket *, uint8_t level, uint8_t optname,
+  void *optval);
+
+int mn_getsockname(struct mn_socket *, struct mn_sockaddr *);
+int mn_getpeername(struct mn_socket *, struct mn_sockaddr *);
+
+int mn_close(struct mn_socket *);
+
+#define mn_socket_set_cbs(sock, cbs) (sock)->ms_cbs = (cbs)
+
+/*
+ * Address conversion
+ */
+int mn_inet_pton(int af, const char *src, void *dst);
+
+#endif /* __SYS_MN_SOCKET_H_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2fbc2b69/sys/mn_socket/include/mn_socket/mn_socket_ops.h
----------------------------------------------------------------------
diff --git a/sys/mn_socket/include/mn_socket/mn_socket_ops.h b/sys/mn_socket/include/mn_socket/mn_socket_ops.h
new file mode 100644
index 0000000..6e768eb
--- /dev/null
+++ b/sys/mn_socket/include/mn_socket/mn_socket_ops.h
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef __SYS_MN_SOCKET_OPS_H_
+#define __SYS_MN_SOCKET_OPS_H_
+
+#include <inttypes.h>
+
+/*
+ * Interface for socket providers.
+ * - mso_create() creates a socket, memory allocation has to be done by
+ *   the socket provider.
+ * - mso_close() closes the socket, memory should be freed. User should not
+ *   be using the socket pointer once it has been closed.
+ */
+struct mn_socket_ops {
+    int (*mso_create)(struct mn_socket **, uint8_t domain, uint8_t type,
+      uint8_t protocol);
+    int (*mso_close)(struct mn_socket *);
+
+    int (*mso_bind)(struct mn_socket *, struct mn_sockaddr *);
+    int (*mso_connect)(struct mn_socket *, struct mn_sockaddr *);
+    int (*mso_listen)(struct mn_socket *, uint8_t qlen);
+
+    int (*mso_sendto)(struct mn_socket *, struct os_mbuf *,
+      struct mn_sockaddr *to);
+    int (*mso_recvfrom)(struct mn_socket *, struct os_mbuf **,
+      struct mn_sockaddr *from);
+
+    int (*mso_getsockopt)(struct mn_socket *, uint8_t level, uint8_t name,
+      void *val);
+    int (*mso_setsockopt)(struct mn_socket *, uint8_t level, uint8_t name,
+      void *val);
+
+    int (*mso_getsockname)(struct mn_socket *, struct mn_sockaddr *);
+    int (*mso_getpeername)(struct mn_socket *, struct mn_sockaddr *);
+};
+
+int mn_socket_ops_reg(const struct mn_socket_ops *ops);
+
+static inline void
+mn_socket_writable(struct mn_socket *s, int error)
+{
+    if (s->ms_cbs && s->ms_cbs->socket.writable) {
+        s->ms_cbs->socket.writable(s, error);
+    }
+}
+
+static inline void
+mn_socket_readable(struct mn_socket *s, int error)
+{
+    if (s->ms_cbs && s->ms_cbs->socket.readable) {
+        s->ms_cbs->socket.readable(s, error);
+    }
+}
+
+static inline int
+mn_socket_newconn(struct mn_socket *s, struct mn_socket *new)
+{
+    if (s->ms_cbs && s->ms_cbs->listen.newconn) {
+        return s->ms_cbs->listen.newconn(s, new);
+    } else {
+        return -1;
+    }
+}
+
+#endif /* __SYS_MN_SOCKET_OPS_H_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2fbc2b69/sys/mn_socket/pkg.yml
----------------------------------------------------------------------
diff --git a/sys/mn_socket/pkg.yml b/sys/mn_socket/pkg.yml
new file mode 100644
index 0000000..0c9c064
--- /dev/null
+++ b/sys/mn_socket/pkg.yml
@@ -0,0 +1,31 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: sys/mn_socket
+pkg.description: Socket interface for Mynewt.
+pkg.author: "Apache Mynewt <de...@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+    - socket
+    - IP
+
+pkg.deps:
+    - libs/os
+    - libs/util
+    - libs/testutil

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2fbc2b69/sys/mn_socket/src/mn_socket.c
----------------------------------------------------------------------
diff --git a/sys/mn_socket/src/mn_socket.c b/sys/mn_socket/src/mn_socket.c
new file mode 100644
index 0000000..2a3602c
--- /dev/null
+++ b/sys/mn_socket/src/mn_socket.c
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <inttypes.h>
+#include <assert.h>
+
+#include <os/os.h>
+
+#include "mn_socket/mn_socket.h"
+#include "mn_socket/mn_socket_ops.h"
+
+/*
+ * Currently there can be just one provider of sockets.
+ */
+static const struct mn_socket_ops *mn_sock_tgt;
+
+int
+mn_socket_ops_reg(const struct mn_socket_ops *ops)
+{
+    if (mn_sock_tgt) {
+        /*
+         * XXXX for now.
+         */
+        return -1;
+    }
+    mn_sock_tgt = ops;
+    return 0;
+}
+
+int
+mn_socket(struct mn_socket **sp, uint8_t domain, uint8_t type, uint8_t proto)
+{
+    int rc;
+
+    *sp = NULL;
+    /*
+     * XXX Look up where socket should go.
+     */
+    if (!mn_sock_tgt) {
+        return MN_EINVAL;
+    }
+    rc = mn_sock_tgt->mso_create(sp, domain, type, proto);
+    if (*sp) {
+        (*sp)->ms_ops = mn_sock_tgt;
+    }
+    return rc;
+}
+
+int
+mn_bind(struct mn_socket *s, struct mn_sockaddr *addr)
+{
+    return s->ms_ops->mso_bind(s, addr);
+}
+
+int
+mn_connect(struct mn_socket *s, struct mn_sockaddr *addr)
+{
+    return s->ms_ops->mso_connect(s, addr);
+}
+
+int
+mn_listen(struct mn_socket *s, uint8_t qlen)
+{
+    return s->ms_ops->mso_listen(s, qlen);
+}
+
+int
+mn_recvfrom(struct mn_socket *s, struct os_mbuf **mp, struct mn_sockaddr *from)
+{
+    return s->ms_ops->mso_recvfrom(s, mp, from);
+}
+
+int
+mn_sendto(struct mn_socket *s, struct os_mbuf *m, struct mn_sockaddr *to)
+{
+    return s->ms_ops->mso_sendto(s, m, to);
+}
+
+int
+mn_getsockopt(struct mn_socket *s, uint8_t level, uint8_t name, void *val)
+{
+    return s->ms_ops->mso_getsockopt(s, level, name, val);
+}
+
+int
+mn_setsockopt(struct mn_socket *s, uint8_t level, uint8_t name, void *val)
+{
+    return s->ms_ops->mso_setsockopt(s, level, name, val);
+}
+
+int
+mn_getsockname(struct mn_socket *s, struct mn_sockaddr *addr)
+{
+    return s->ms_ops->mso_getsockname(s, addr);
+}
+
+int
+mn_getpeername(struct mn_socket *s, struct mn_sockaddr *addr)
+{
+    return s->ms_ops->mso_getpeername(s, addr);
+}
+
+int
+mn_close(struct mn_socket *s)
+{
+    return s->ms_ops->mso_close(s);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2fbc2b69/sys/mn_socket/src/mn_socket_aconv.c
----------------------------------------------------------------------
diff --git a/sys/mn_socket/src/mn_socket_aconv.c b/sys/mn_socket/src/mn_socket_aconv.c
new file mode 100644
index 0000000..5053eac
--- /dev/null
+++ b/sys/mn_socket/src/mn_socket_aconv.c
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <ctype.h>
+#include <os/queue.h>
+#include "mn_socket/mn_socket.h"
+
+int
+mn_inet_pton(int af, const char *src, void *dst)
+{
+    const char *ch_src;
+    uint8_t *ch_tgt;
+    int val;
+    int cnt;
+
+    if (af == MN_PF_INET) {
+        cnt = 0;
+        ch_tgt = dst;
+        val = 0;
+        for (ch_src = src; *ch_src; ch_src++) {
+            if (cnt > 4) {
+                return 0;
+            }
+            if (isdigit(*ch_src)) {
+                val = val * 10 + *ch_src - '0';
+                if (val > 255) {
+                    return 0;
+                }
+                *ch_tgt = val;
+            } else if (*ch_src == '.') {
+                ++cnt;
+                val = 0;
+                ch_tgt++;
+            } else {
+                return 0;
+            }
+        }
+        return 1;
+    } else {
+        return MN_EAFNOSUPPORT;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2fbc2b69/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
new file mode 100644
index 0000000..a8d9cc2
--- /dev/null
+++ b/sys/mn_socket/src/test/mn_sock_test.c
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <os/os.h>
+#include <testutil/testutil.h>
+
+#include "mn_socket/mn_socket.h"
+
+TEST_CASE(inet_pton_test)
+{
+    int rc;
+    uint8_t addr[8];
+    struct test_vec {
+        char *str;
+        uint8_t cmp[4];
+    };
+    struct test_vec ok_vec[] = {
+        { "1.1.1.1", { 1, 1, 1, 1 } },
+        { "1.2.3.4", { 1, 2, 3, 4 } },
+        { "010.001.255.255", { 10, 1, 255, 255 } },
+        { "001.002.005.006", { 1, 2, 5, 6 } }
+    };
+    struct test_vec invalid_vec[] = {
+        { "a.b.c.d" },
+        { "1a.b3.4.2" },
+        { "1.3.4.2a" },
+        { "1111.3.4.2" },
+        { "3.256.1.0" },
+    };
+    int i;
+
+    for (i = 0; i < sizeof(ok_vec) / sizeof(ok_vec[0]); i++) {
+        memset(addr, 0xa5, sizeof(addr));
+        rc = mn_inet_pton(MN_PF_INET, ok_vec[i].str, addr);
+        TEST_ASSERT(rc == 1);
+        TEST_ASSERT(!memcmp(ok_vec[i].cmp, addr, sizeof(uint32_t)));
+        TEST_ASSERT(addr[5] == 0xa5);
+    }
+    for (i = 0; i < sizeof(invalid_vec) / sizeof(invalid_vec[0]); i++) {
+        rc = mn_inet_pton(MN_PF_INET, invalid_vec[i].str, addr);
+        TEST_ASSERT(rc == 0);
+    }
+}
+
+TEST_SUITE(mn_socket_test_all)
+{
+    inet_pton_test();
+}
+
+#ifdef MYNEWT_SELFTEST
+
+int
+main(int argc, char **argv)
+{
+    tu_config.tc_print_results = 1;
+    tu_init();
+
+    mn_socket_test_all();
+
+    return tu_any_failed;
+}
+#endif
+