This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 7d33f73 libs/libc/net: implement socketpair
7d33f73 is described below
commit 7d33f73e27a503d7a2485771f2636a32a73769ad
Author: danguanghua <[email protected]>
AuthorDate: Thu Dec 24 14:42:34 2020 +0800
libs/libc/net: implement socketpair
N/A
Reference here:
https://www.freebsd.org/cgi/man.cgi?apropos=0&sektion=2&query=socketpair&manpath=FreeBSD+7.0-current&format=html
Change-Id: I959b4d661cd436f5d5050baf9e821db84139d482
Signed-off-by: danguanghua <[email protected]>
---
include/sys/socket.h | 1 +
libs/libc/net/Make.defs | 2 +-
libs/libc/net/lib_socketpair.c | 186 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 188 insertions(+), 1 deletion(-)
diff --git a/include/sys/socket.h b/include/sys/socket.h
index 0de1b44..bb8fa58 100644
--- a/include/sys/socket.h
+++ b/include/sys/socket.h
@@ -379,6 +379,7 @@ extern "C"
#endif
int socket(int domain, int type, int protocol);
+int socketpair(int domain, int type, int protocol, int sv[2]);
int bind(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen);
int connect(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen);
diff --git a/libs/libc/net/Make.defs b/libs/libc/net/Make.defs
index 4820b9d..ff0b663 100644
--- a/libs/libc/net/Make.defs
+++ b/libs/libc/net/Make.defs
@@ -41,7 +41,7 @@ CSRCS += lib_inetntop.c lib_inetpton.c
CSRCS += lib_etherntoa.c lib_etheraton.c
ifeq ($(CONFIG_NET),y)
-CSRCS += lib_recvmsg.c lib_sendmsg.c lib_shutdown.c
+CSRCS += lib_recvmsg.c lib_sendmsg.c lib_shutdown.c lib_socketpair.c
endif
ifeq ($(CONFIG_NET_LOOPBACK),y)
diff --git a/libs/libc/net/lib_socketpair.c b/libs/libc/net/lib_socketpair.c
new file mode 100644
index 0000000..3bae979
--- /dev/null
+++ b/libs/libc/net/lib_socketpair.c
@@ -0,0 +1,186 @@
+/****************************************************************************
+ * libs/libc/net/lib_socketpair.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+/****************************************************************************
+ * Public Type Declarations
+ ****************************************************************************/
+
+union sockaddr_u
+{
+ struct sockaddr addr;
+ struct sockaddr_in inaddr;
+ struct sockaddr_in6 in6addr;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline void init_loop_addr(int domain, FAR union sockaddr_u *addr,
+ FAR socklen_t *len)
+{
+ if (domain == AF_INET6)
+ {
+ struct in6_addr init_sin6_addr = IN6ADDR_LOOPBACK_INIT;
+
+ memset(&addr->in6addr, 0, sizeof(addr->in6addr));
+ addr->in6addr.sin6_family = domain;
+ addr->in6addr.sin6_addr = init_sin6_addr;
+ *len = sizeof(addr->in6addr);
+ }
+ else
+ {
+ memset(&addr->inaddr, 0, sizeof(addr->inaddr));
+ addr->inaddr.sin_family = domain;
+ addr->inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ *len = sizeof(addr->inaddr);
+ }
+}
+
+static int create_socket(int domain, int type, int protocol,
+ FAR union sockaddr_u *addr, FAR socklen_t *len)
+{
+ int socketfd;
+
+ socketfd = socket(domain, type, protocol);
+ if (socketfd < 0)
+ {
+ return socketfd;
+ }
+
+ init_loop_addr(domain, addr, len);
+ if (bind(socketfd, &addr->addr, *len) == 0)
+ {
+ if (getsockname(socketfd, &addr->addr, len) == 0)
+ {
+ return socketfd;
+ }
+ }
+
+ close(socketfd);
+ return -1;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: socketpair
+ *
+ * Description:
+ * Create an unbound pair of connected sockets in a specified domain, of a
+ * specified type, under the protocol optionally specified by the protocol
+ * argument. The two sockets shall be identical. The file descriptors used
+ * in referencing the created sockets shall be returned in
+ * sv[0] and sv[1].
+ *
+ ****************************************************************************/
+
+int socketpair(int domain, int type, int protocol, int sv[2])
+{
+ union sockaddr_u addr[2];
+ socklen_t len;
+
+ if (domain != AF_UNIX && domain != AF_INET && domain != AF_INET6)
+ {
+ set_errno(EAFNOSUPPORT);
+ return -1;
+ }
+
+ if (sv == NULL)
+ {
+ set_errno(EINVAL);
+ return -1;
+ }
+
+ if (domain == AF_UNIX)
+ {
+ domain = AF_INET;
+ }
+
+ sv[0] = create_socket(domain, type, protocol, &addr[0], &len);
+ sv[1] = create_socket(domain, type, protocol, &addr[1], &len);
+ if (sv[0] < 0 || sv[1] < 0)
+ {
+ goto err;
+ }
+
+ if (type == SOCK_DGRAM)
+ {
+ if (connect(sv[0], &addr[1].addr, len) < 0)
+ {
+ goto err;
+ }
+
+ if (connect(sv[1], &addr[0].addr, len) < 0)
+ {
+ goto err;
+ }
+ }
+ else
+ {
+ int listener = sv[0];
+
+ if (listen(listener, 2) < 0)
+ {
+ goto err;
+ }
+
+ if (connect(sv[1], &addr[0].addr, len) < 0)
+ {
+ goto err;
+ }
+
+ sv[0] = accept(listener, &addr[0].addr, &len);
+ close(listener);
+ if (sv[0] < 0)
+ {
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ if (sv[0] != -1)
+ {
+ close(sv[0]);
+ }
+
+ if (sv[1] != -1)
+ {
+ close(sv[1]);
+ }
+
+ return -1;
+}