Hi all, I checked in the first take of the socket interface.
I did change it a bit from my original email. Notably; the user of the socket will not allocate the memory for socket. This would be done by the system. The API uses callbacks instead of struct os_event automatically. As discussed socket user can/should convert this to an event and then make calls to socket from the context of their task. Also I ended up using os_mbufs for sending/receiving data. This will allow us to have zero-copy IP stack, assuming the stack uses os_mbufs. At the moment I’m testing this API using Arduino MKR1000, using it’s internal IP stack and sockets. The driver for the WiFi chip is checked in to mynewt_arduino_zero repository, as that’s where the BSP for the board is as well. From license point of view the driver could be brought over to mynewt-core, but I felt it should go together with the BSP. > Begin forwarded message: > > From: [email protected] > Subject: incubator-mynewt-core git commit: MYNEWT-314; First take on the > socket interface. > Date: July 11, 2016 at 5:03:10 PM PDT > To: [email protected] > Reply-To: [email protected] > > Repository: incubator-mynewt-core > Updated Branches: > refs/heads/develop 364bcc3ea -> eb24b4d83 > > > 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/eb24b4d8 > Tree: > http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/eb24b4d8 > Diff: > http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/eb24b4d8 > > Branch: refs/heads/develop > Commit: eb24b4d83ed37126c567de62903eac55600a4052 > Parents: 364bcc3 > Author: Marko Kiiskila <[email protected]> > Authored: Mon Jul 11 16:59:46 2016 -0700 > Committer: Marko Kiiskila <[email protected]> > Committed: Mon Jul 11 16:59:46 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/eb24b4d8/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/eb24b4d8/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/eb24b4d8/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 <[email protected]>" > +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/eb24b4d8/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/eb24b4d8/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/eb24b4d8/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 > + >
