Socket interface: Added getsockname[C() interfaces.

This commit is contained in:
Gregory Nutt 2017-07-14 09:04:19 -06:00
parent ac72978072
commit ac543648b8
8 changed files with 276 additions and 378 deletions

View File

@ -116,6 +116,8 @@ struct sock_intf_s
CODE void (*si_addref)(FAR struct socket *psock);
CODE int (*si_bind)(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
CODE int (*si_getsockname)(FAR struct socket *psock,
FAR struct sockaddr *addr, FAR socklen_t *addrlen);
CODE int (*si_listen)(FAR struct socket *psock, int backlog);
CODE int (*si_connect)(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);

View File

@ -69,8 +69,8 @@ int psock_local_bind(FAR struct socket *psock,
(FAR const struct sockaddr_un *)addr;
int namelen;
DEBUGASSERT(psock && psock->s_conn && unaddr &&
unaddr->sun_family == AF_LOCAL &&
DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
unaddr != NULL && unaddr->sun_family == AF_LOCAL &&
addrlen >= sizeof(sa_family_t));
conn = (FAR struct local_conn_s *)psock->s_conn;
@ -79,7 +79,7 @@ int psock_local_bind(FAR struct socket *psock,
conn->lc_proto = psock->s_type;
/* No determine the type of the Unix domain socket by comparing the size
/* Now determine the type of the Unix domain socket by comparing the size
* of the address description.
*/

View File

@ -63,6 +63,8 @@ static sockcaps_t local_sockcaps(FAR struct socket *psock);
static void local_addref(FAR struct socket *psock);
static int local_bind(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
static int local_getsockname(FAR struct socket *psock,
FAR struct sockaddr *addr, FAR socklen_t *addrlen);
static int local_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
static ssize_t local_send(FAR struct socket *psock, FAR const void *buf,
@ -82,6 +84,7 @@ const struct sock_intf_s g_local_sockif =
local_sockcaps, /* si_sockcaps */
local_addref, /* si_addref */
local_bind, /* si_bind */
local_getsockname, /* si_getsockname */
local_listen, /* si_listen */
local_connect, /* si_connect */
local_accept, /* si_accept */
@ -303,6 +306,87 @@ static int local_bind(FAR struct socket *psock,
return ret;
}
/****************************************************************************
* Name: local_getsockname
*
* Description:
* The local_getsockname() function retrieves the locally-bound name of
* the specified local socket, stores this address in the sockaddr
* structure pointed to by the 'addr' argument, and stores the length of
* this address in the object pointed to by the 'addrlen' argument.
*
* If the actual length of the address is greater than the length of the
* supplied sockaddr structure, the stored address will be truncated.
*
* If the socket has not been bound to a local name, the value stored in
* the object pointed to by address is unspecified.
*
* Parameters:
* psock Socket structure of the socket to be queried
* addr sockaddr structure to receive data [out]
* addrlen Length of sockaddr structure [in/out]
*
* Returned Value:
* On success, 0 is returned, the 'addr' argument points to the address
* of the socket, and the 'addrlen' argument points to the length of the
* address. Otherwise, a negated errno value is returned. See
* getsockname() for the list of appropriate error numbers.
*
****************************************************************************/
static int local_getsockname(FAR struct socket *psock,
FAR struct sockaddr *addr,
FAR socklen_t *addrlen)
{
FAR const struct sockaddr_un *unaddr =
(FAR const struct sockaddr_un *)addr;
FAR struct local_conn_s *conn;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
unaddr != NULL && addrlen != NULL &&
*addrlen >= sizeof(sa_family_t));
if (*addrlen < sizeof(sa_family_t))
{
/* This is apparently not an error */
*addrlen = 0;
return OK;
}
conn = (FAR struct local_conn_s *)psock->s_conn;
/* Save the address family */
unaddr->sun_family = AF_LOCAL;
if (*addrlen > sizeof(sa_family_t))
{
/* Now copy the address description. */
if (conn->lc_type == LOCAL_TYPE_UNNAMED)
{
/* Zero-length sun_path... This is an abstract Unix domain socket */
*addrlen = sizeof(sa_family_t);
}
else /* conn->lctype = LOCAL_TYPE_PATHNAME */
{
/* Get the available length in the user-provided buffer. */
int pathlen = *addrlen - sizeof(sa_family_t);
/* Copy the path into the user address structure */
(void)strncpy(unaddr->sun_path, conn->lc_path, pathlen);
unaddr->sun_path[pathlen - 1] = '\0';
*addrlen = sizeof(sa_family_t) + namelen;
}
}
return OK;
}
/****************************************************************************
* Name: local_connect
*

View File

@ -63,6 +63,8 @@ static sockcaps_t pkt_sockcaps(FAR struct socket *psock);
static void pkt_addref(FAR struct socket *psock);
static int pkt_bind(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
static int pkt_getsockname(FAR struct socket *psock,
FAR struct sockaddr *addr, FAR socklen_t *addrlen);
static int pkt_listen(FAR struct socket *psock, int backlog);
static int pkt_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
@ -85,6 +87,7 @@ const struct sock_intf_s g_pkt_sockif =
pkt_sockcaps, /* si_sockcaps */
pkt_addref, /* si_addref */
pkt_bind, /* si_bind */
pkt_getsockname, /* si_getsockname */
pkt_listen, /* si_listen */
pkt_connect, /* si_connect */
pkt_accept, /* si_accept */
@ -378,6 +381,40 @@ static int pkt_bind(FAR struct socket *psock, FAR const struct sockaddr *addr,
}
}
/****************************************************************************
* Name: pkt_getsockname
*
* Description:
* The pkt_getsockname() function retrieves the locally-bound name of the
* specified packet socket, stores this address in the sockaddr structure
* pointed to by the 'addr' argument, and stores the length of this
* address in the object pointed to by the 'addrlen' argument.
*
* If the actual length of the address is greater than the length of the
* supplied sockaddr structure, the stored address will be truncated.
*
* If the socket has not been bound to a local name, the value stored in
* the object pointed to by address is unspecified.
*
* Parameters:
* psock Socket structure of the socket to be queried
* addr sockaddr structure to receive data [out]
* addrlen Length of sockaddr structure [in/out]
*
* Returned Value:
* On success, 0 is returned, the 'addr' argument points to the address
* of the socket, and the 'addrlen' argument points to the length of the
* address. Otherwise, a negated errno value is returned. See
* getsockname() for the list of appropriate error numbers.
*
****************************************************************************/
static int pkt_getsockname(FAR struct socket *psock,
FAR struct sockaddr *addr, FAR socklen_t *addrlen)
{
return -EAFNOSUPPORT;
}
/****************************************************************************
* Name: pkt_listen
*

View File

@ -49,6 +49,14 @@ else ifeq ($(CONFIG_NET_IPv6),y)
SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_connect.c inet_close.c
endif
ifeq ($(CONFIG_NET_IPv4),y)
SOCK_CSRCS += ipv4_getsockname.c
endif
ifeq ($(CONFIG_NET_IPv6),y)
SOCK_CSRCS += ipv6_getsockname.c
endif
# TCP/IP support
ifeq ($(CONFIG_NET_TCP),y)

View File

@ -47,308 +47,11 @@
#include <assert.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/udp.h>
#include "utils/utils.h"
#include "netdev/netdev.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "socket/socket.h"
#include "usrsock/usrsock.h"
#ifdef CONFIG_NET
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: get_ipv4_sockname
*
* Description:
* The getsockname() function retrieves the locally-bound name of the
* specified PF_NET socket.
*
* Parameters:
* psock Point to the socket structure instance [in]
* addr sockaddr structure to receive data [out]
* addrlen Length of sockaddr structure [in/out]
*
* Returned Value:
* On success, 0 is returned, the 'addr' argument points to the address
* of the socket, and the 'addrlen' argument points to the length of the
* address. Otherwise, -1 is returned and errno is set to indicate the error.
* Possible errno values that may be returned include:
*
* EBADF - The socket argument is not a valid file descriptor.
* EOPNOTSUPP - The operation is not supported for this socket's protocol.
* EINVAL - The socket has been shut down.
*
* Assumptions:
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen)
{
FAR struct net_driver_s *dev;
#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
FAR struct sockaddr_in *outaddr = (FAR struct sockaddr_in *)addr;
#endif
#ifdef CONFIG_NETDEV_MULTINIC
in_addr_t lipaddr;
in_addr_t ripaddr;
#endif
/* Check if enough space has been provided for the full address */
if (*addrlen < sizeof(struct sockaddr_in))
{
/* This function is supposed to return the partial address if
* a smaller buffer has been provided. This support has not
* been implemented.
*/
return -ENOSYS;
}
/* Set the port number */
switch (psock->s_type)
{
#ifdef NET_TCP_HAVE_STACK
case SOCK_STREAM:
{
FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn;
outaddr->sin_port = tcp_conn->lport; /* Already in network byte order */
#ifdef CONFIG_NETDEV_MULTINIC
lipaddr = tcp_conn->u.ipv4.laddr;
ripaddr = tcp_conn->u.ipv4.raddr;
#endif
}
break;
#endif
#ifdef NET_UDP_HAVE_STACK
case SOCK_DGRAM:
{
FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn;
outaddr->sin_port = udp_conn->lport; /* Already in network byte order */
#ifdef CONFIG_NETDEV_MULTINIC
lipaddr = udp_conn->u.ipv4.laddr;
ripaddr = udp_conn->u.ipv4.raddr;
#endif
}
break;
#endif
default:
return -EOPNOTSUPP;
}
#ifdef CONFIG_NETDEV_MULTINIC
/* The socket/connection does not know its IP address unless
* CONFIG_NETDEV_MULTINIC is selected. Otherwise the design supports only
* a single network device and only the network device knows the IP address.
*/
if (lipaddr == 0)
{
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
outaddr->sin_family = AF_INET;
outaddr->sin_addr.s_addr = 0;
*addrlen = sizeof(struct sockaddr_in);
#endif
return OK;
}
#endif
net_lock();
#ifdef CONFIG_NETDEV_MULTINIC
/* Find the device matching the IPv4 address in the connection structure.
* NOTE: listening sockets have no ripaddr. Work around is to use the
* lipaddr when ripaddr is not available.
*/
if (ripaddr == 0)
{
ripaddr = lipaddr;
}
dev = netdev_findby_ipv4addr(lipaddr, ripaddr);
#else
/* There is only one, the first network device in the list. */
dev = g_netdevices;
#endif
if (!dev)
{
net_unlock();
return -EINVAL;
}
/* Set the address family and the IP address */
#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
outaddr->sin_family = AF_INET;
outaddr->sin_addr.s_addr = dev->d_ipaddr;
*addrlen = sizeof(struct sockaddr_in);
#endif
net_unlock();
/* Return success */
return OK;
}
#endif
/****************************************************************************
* Name: ipv6_getsockname
*
* Description:
* The getsockname() function retrieves the locally-bound name of the
* specified PF_NET6 socket.
*
* Parameters:
* psock Point to the socket structure instance [in]
* addr sockaddr structure to receive data [out]
* addrlen Length of sockaddr structure [in/out]
*
* Returned Value:
* On success, 0 is returned, the 'addr' argument points to the address
* of the socket, and the 'addrlen' argument points to the length of the
* address. Otherwise, -1 is returned and errno is set to indicate the error.
* Possible errno values that may be returned include:
*
* EBADF - The socket argument is not a valid file descriptor.
* EOPNOTSUPP - The operation is not supported for this socket's protocol.
* EINVAL - The socket has been shut down.
*
* Assumptions:
*
****************************************************************************/
#ifdef CONFIG_NET_IPv6
int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen)
{
FAR struct net_driver_s *dev;
#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
FAR struct sockaddr_in6 *outaddr = (FAR struct sockaddr_in6 *)addr;
#endif
#ifdef CONFIG_NETDEV_MULTINIC
net_ipv6addr_t *lipaddr;
net_ipv6addr_t *ripaddr;
#endif
/* Check if enough space has been provided for the full address */
if (*addrlen < sizeof(struct sockaddr_in6))
{
/* This function is supposed to return the partial address if
* a smaller buffer has been provided. This support has not
* been implemented.
*/
return -ENOSYS;
}
/* Set the port number */
switch (psock->s_type)
{
#ifdef NET_TCP_HAVE_STACK
case SOCK_STREAM:
{
FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn;
outaddr->sin6_port = tcp_conn->lport; /* Already in network byte order */
#ifdef CONFIG_NETDEV_MULTINIC
lipaddr = &tcp_conn->u.ipv6.laddr;
ripaddr = &tcp_conn->u.ipv6.raddr;
#endif
}
break;
#endif
#ifdef NET_UDP_HAVE_STACK
case SOCK_DGRAM:
{
FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn;
outaddr->sin6_port = udp_conn->lport; /* Already in network byte order */
#ifdef CONFIG_NETDEV_MULTINIC
lipaddr = &udp_conn->u.ipv6.laddr;
ripaddr = &udp_conn->u.ipv6.raddr;
#endif
}
break;
#endif
default:
return -EOPNOTSUPP;
}
#ifdef CONFIG_NETDEV_MULTINIC
/* The socket/connection does not know its IP address unless
* CONFIG_NETDEV_MULTINIC is selected. Otherwise the design supports only
* a single network device and only the network device knows the IP address.
*/
if (net_ipv6addr_cmp(lipaddr, g_ipv6_allzeroaddr))
{
#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
outaddr->sin6_family = AF_INET6;
memcpy(outaddr->sin6_addr.in6_u.u6_addr8, g_ipv6_allzeroaddr, 16);
*addrlen = sizeof(struct sockaddr_in6);
#endif
return OK;
}
#endif
net_lock();
#ifdef CONFIG_NETDEV_MULTINIC
/* Find the device matching the IPv6 address in the connection structure.
* NOTE: listening sockets have no ripaddr. Work around is to use the
* lipaddr when ripaddr is not available.
*/
if (net_ipv6addr_cmp(ripaddr, g_ipv6_allzeroaddr))
{
ripaddr = lipaddr;
}
dev = netdev_findby_ipv6addr(*lipaddr, *ripaddr);
#else
/* There is only one, the first network device in the list. */
dev = g_netdevices;
#endif
if (!dev)
{
net_unlock();
return -EINVAL;
}
/* Set the address family and the IP address */
#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK)
outaddr->sin6_family = AF_INET6;
memcpy(outaddr->sin6_addr.in6_u.u6_addr8, dev->d_ipv6addr, 16);
*addrlen = sizeof(struct sockaddr_in6);
#endif
net_unlock();
/* Return success */
return OK;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -380,10 +83,11 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
* Possible errno values that may be returned include:
*
* EBADF - The socket argument is not a valid file descriptor.
* ENOTSOCK - The socket argument does not refer to a socket.
* EOPNOTSUPP - The operation is not supported for this socket's protocol.
* EINVAL - The socket has been shut down.
*
* Assumptions:
* ENOBUFS - Insufficient resources were available in the system to
* complete the function.
*
****************************************************************************/
@ -395,7 +99,7 @@ int getsockname(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen)
/* Verify that the sockfd corresponds to valid, allocated socket */
if (!psock || psock->s_crefs <= 0)
if (psock == NULL || psock->s_crefs <= 0)
{
errcode = EBADF;
goto errout;
@ -406,54 +110,19 @@ int getsockname(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen)
*/
#ifdef CONFIG_DEBUG_FEATURES
if (!addr || !addrlen)
if (addr == NULL || addrlen <= 0)
{
errcode = EINVAL;
goto errout;
}
#endif
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
FAR struct usrsock_conn_s *conn = psock->s_conn;
/* Let the address family's send() method handle the operation */
DEBUGASSERT(conn);
DEBUGASSERT(psock->s_sockif != NULL &&
psock->s_sockif->si_getsockname != NULL);
/* Handle usrsock getsockname */
ret = usrsock_getsockname(conn, addr, addrlen);
if (ret < 0)
{
errcode = -ret;
goto errout;
}
return OK;
}
#endif
/* Handle by address domain */
switch (psock->s_domain)
{
#ifdef CONFIG_NET_IPv4
case PF_INET:
ret = ipv4_getsockname(psock, addr, addrlen);
break;
#endif
#ifdef CONFIG_NET_IPv6
case PF_INET6:
ret = ipv6_getsockname(psock, addr, addrlen);
break;
#endif
case PF_PACKET:
default:
errcode = EAFNOSUPPORT;
goto errout;
}
ret = psock->s_sockif->si_getsockname(psock, addr, addrlen);
/* Check for failure */

View File

@ -63,6 +63,8 @@ static sockcaps_t inet_sockcaps(FAR struct socket *psock);
static void inet_addref(FAR struct socket *psock);
static int inet_bind(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
static int inet_getsockname(FAR struct socket *psock,
FAR struct sockaddr *addr, FAR socklen_t *addrlen);
static int inet_listen(FAR struct socket *psock, int backlog);
static int inet_accept(FAR struct socket *psock,
FAR struct sockaddr *addr, FAR socklen_t *addrlen,
@ -83,6 +85,7 @@ const struct sock_intf_s g_inet_sockif =
inet_sockcaps, /* si_sockcaps */
inet_addref, /* si_addref */
inet_bind, /* si_bind */
inet_getsockname, /* si_getsockname */
inet_listen, /* si_listen */
inet_connect, /* si_connect */
inet_accept, /* si_accept */
@ -544,6 +547,72 @@ static int inet_bind(FAR struct socket *psock,
return ret;
}
/****************************************************************************
* Name: inet_getsockname
*
* Description:
* The inet_getsockname() function retrieves the locally-bound name of
* the specified INET socket, stores this address in the sockaddr
* structure pointed to by the 'addr' argument, and stores the length of
* this address in the object pointed to by the 'addrlen' argument.
*
* If the actual length of the address is greater than the length of the
* supplied sockaddr structure, the stored address will be truncated.
*
* If the socket has not been bound to a local name, the value stored in
* the object pointed to by address is unspecified.
*
* Parameters:
* psock Socket structure of the socket to be queried
* addr sockaddr structure to receive data [out]
* addrlen Length of sockaddr structure [in/out]
*
* Returned Value:
* On success, 0 is returned, the 'addr' argument points to the address
* of the socket, and the 'addrlen' argument points to the length of the
* address. Otherwise, a negated errno value is returned. See
* getsockname() for the list of appropriate error numbers.
*
****************************************************************************/
static int inet_getsockname(FAR struct socket *psock,
FAR struct sockaddr *addr,
FAR socklen_t *addrlen)
{
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
FAR struct usrsock_conn_s *conn = psock->s_conn;
DEBUGASSERT(conn != NULL);
/* Handle usrsock getsockname */
return usrsock_getsockname(conn, addr, addrlen);
}
#endif
/* Handle by address domain */
switch (psock->s_domain)
{
#ifdef CONFIG_NET_IPv4
case PF_INET:
return ipv4_getsockname(psock, addr, addrlen);
break;
#endif
#ifdef CONFIG_NET_IPv6
case PF_INET6:
return ipv6_getsockname(psock, addr, addrlen);
break;
#endif
default:
return -EAFNOSUPPORT;
}
}
/****************************************************************************
* Name: inet_listen
*

View File

@ -436,6 +436,35 @@ int net_timeo(systime_t start_time, socktimeo_t timeo);
ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
int flags);
/****************************************************************************
* Name: ipv4_getsockname and ipv6_sockname
*
* Description:
* The ipv4_getsockname() and ipv6_getsocknam() function retrieve the
* locally-bound name of the specified INET socket.
*
* Parameters:
* psock Point to the socket structure instance [in]
* addr sockaddr structure to receive data [out]
* addrlen Length of sockaddr structure [in/out]
*
* Returned Value:
* On success, 0 is returned, the 'addr' argument points to the address
* of the socket, and the 'addrlen' argument points to the length of the
* address. Otherwise, a negated errno value is returned. See
* getsockname() for the list of returned error values.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen);
#endif
#ifdef CONFIG_NET_IPv6
int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen);
#endif
/****************************************************************************
* Name: inet_connect
*