Skip to content
Permalink
Browse files

net: sockets: implement getsockname function

From POSIX.1-2017:

The getsockname() function shall retrieve the locally-bound name of the
specified socket, store this address in the sockaddr structure pointed
to by the address argument, and store the length of this address in the
object pointed to by the address_len argument.

The address_len argument points to a socklen_t object which on input
specifies the length of the supplied sockaddr structure, and on output
specifies the length of the stored address. If the actual length of the
address is greater than the length of the supplied sockaddr structure,
the stored address shall 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.

Signed-off-by: Tomasz Gorochowik <tgorochowik@antmicro.com>
  • Loading branch information...
tgorochowik authored and jukkar committed May 10, 2019
1 parent fb713aa commit c0b30355fb826c0bcb9691ae43425ce1a044b496
Showing with 117 additions and 0 deletions.
  1. +1 −0 include/misc/fdtable.h
  2. +21 −0 include/net/socket.h
  3. +94 −0 subsys/net/lib/sockets/sockets.c
  4. +1 −0 subsys/net/lib/sockets/sockets_tls.c
@@ -140,6 +140,7 @@ enum {
ZFD_IOCTL_LSEEK,
ZFD_IOCTL_POLL_PREPARE,
ZFD_IOCTL_POLL_UPDATE,
ZFD_IOCTL_GETSOCKNAME,
};

#ifdef __cplusplus
@@ -370,6 +370,21 @@ int zsock_getsockopt(int sock, int level, int optname,
int zsock_setsockopt(int sock, int level, int optname,
const void *optval, socklen_t optlen);

/**
* @brief Get socket name
*
* @details
* @rststar
* See `POSIX.1-2017 article
* <http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html>`__
* for normative description.
* This function is also exposed as ``getsockname()``
* if :option:`CONFIG_NET_SOCKETS_POSIX_NAMES` is defined.
* @endrststar
*/
__syscall int zsock_getsockname(int sock, struct sockaddr *addr,
socklen_t *addrlen);

/**
* @brief Get local host name
*
@@ -605,6 +620,12 @@ static inline int setsockopt(int sock, int level, int optname,
return zsock_setsockopt(sock, level, optname, optval, optlen);
}

static inline int getsockname(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
return zsock_getsockname(sock, addr, addrlen);
}

static inline int getaddrinfo(const char *host, const char *service,
const struct zsock_addrinfo *hints,
struct zsock_addrinfo **res)
@@ -1158,6 +1158,90 @@ int zsock_setsockopt(int sock, int level, int optname,
VTABLE_CALL(setsockopt, sock, level, optname, optval, optlen);
}

int zsock_getsockname_ctx(struct net_context *ctx, struct sockaddr *addr,
socklen_t *addrlen)
{
socklen_t newlen = 0;

/* If we don't have a connection handler, the socket is not bound */
if (ctx->conn_handler) {
SET_ERRNO(EINVAL);
}

if (IS_ENABLED(CONFIG_NET_IPV4) && ctx->local.family == AF_INET) {
struct sockaddr_in addr4;

addr4.sin_family = AF_INET;
addr4.sin_port = net_sin_ptr(&ctx->local)->sin_port;
memcpy(&addr4.sin_addr, net_sin_ptr(&ctx->local)->sin_addr,
sizeof(struct in_addr));
newlen = sizeof(struct sockaddr_in);

memcpy(addr, &addr4, MIN(*addrlen, newlen));
} else if (IS_ENABLED(CONFIG_NET_IPV6) &&
ctx->local.family == AF_INET6) {
struct sockaddr_in6 addr6;

addr6.sin6_family = AF_INET6;
addr6.sin6_port = net_sin6_ptr(&ctx->local)->sin6_port;
memcpy(&addr6.sin6_addr, net_sin6_ptr(&ctx->local)->sin6_addr,
sizeof(struct in6_addr));
newlen = sizeof(struct sockaddr_in6);

memcpy(addr, &addr6, MIN(*addrlen, newlen));
} else {
SET_ERRNO(EINVAL);
}

*addrlen = newlen;

return 0;
}

int z_impl_zsock_getsockname(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
const struct fd_op_vtable *vtable;
void *ctx = z_get_fd_obj_and_vtable(sock, &vtable);

if (ctx == NULL) {
return -1;
}

NET_DBG("getsockname: ctx=%p, fd=%d", ctx, sock);

return z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_GETSOCKNAME,
addr, addrlen);
}

#ifdef CONFIG_USERSPACE
Z_SYSCALL_HANDLER(zsock_getsockname, sock, addr, addrlen)
{
socklen_t addrlen_copy;
int ret;

Z_OOPS(z_user_from_copy(&addrlen_copy, (void *)addrlen,
sizeof(socklen_t)));

if (Z_SYSCALL_MEMORY_WRITE(addr, addrlen_copy)) {
errno = EFAULT;
return -1;
}

ret = z_impl_zsock_getsockname(sock, (struct sockaddr *)addr,
&addrlen_copy);

if (ret == 0 &&
z_user_to_copy((void *)addrlen, &addrlen_copy,
sizeof(socklen_t))) {
errno = EINVAL;
return -1;
}

return ret;
}
#endif /* CONFIG_USERSPACE */

static ssize_t sock_read_vmeth(void *obj, void *buffer, size_t count)
{
return zsock_recvfrom_ctx(obj, buffer, count, 0, NULL, 0);
@@ -1219,6 +1303,16 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, va_list args)
return zsock_poll_update_ctx(obj, pfd, pev);
}

case ZFD_IOCTL_GETSOCKNAME: {
struct sockaddr *addr;
socklen_t *addrlen;

addr = va_arg(args, struct sockaddr *);
addrlen = va_arg(args, socklen_t *);

return zsock_getsockname_ctx(obj, addr, addrlen);
}

default:
errno = EOPNOTSUPP;
return -1;
@@ -1916,6 +1916,7 @@ static int tls_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args)
/* fcntl() commands */
case F_GETFL:
case F_SETFL:
case ZFD_IOCTL_GETSOCKNAME:
/* Pass the call to the core socket implementation. */
return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args);

0 comments on commit c0b3035

Please sign in to comment.
You can’t perform that action at this time.