Skip to content

Commit

Permalink
net: sockets: implement getsockname function
Browse files Browse the repository at this point in the history
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 17, 2019
1 parent fb713aa commit c0b3035
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/misc/fdtable.h
Expand Up @@ -140,6 +140,7 @@ enum {
ZFD_IOCTL_LSEEK,
ZFD_IOCTL_POLL_PREPARE,
ZFD_IOCTL_POLL_UPDATE,
ZFD_IOCTL_GETSOCKNAME,
};

#ifdef __cplusplus
Expand Down
21 changes: 21 additions & 0 deletions include/net/socket.h
Expand Up @@ -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
*
Expand Down Expand Up @@ -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)
Expand Down
94 changes: 94 additions & 0 deletions subsys/net/lib/sockets/sockets.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions subsys/net/lib/sockets/sockets_tls.c
Expand Up @@ -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);

Expand Down

0 comments on commit c0b3035

Please sign in to comment.