8.3.1.2. Get remote host/port operations
Note
Code related to this tutorial can be found under examples/custom-network/remote-host-port in the Anjay source directory.
8.3.1.2.1. Introduction
This tutorial builds up on the previous one and adds support for the “get remote host” and “get remote port” operations.
This will allow CoAP response cache to work and the anjay_configuration_t::msg_cache_size configuration option to be properly respected.
This is necessary because the response cache is shared between all the server connections, and remote host/port pairs are used to distinguish between them in the cache storage - and these functions are used to retrieve this information from sockets.
8.3.1.2.2. Get remote host operation
#include <arpa/inet.h>
// ...
typedef union {
struct sockaddr addr;
struct sockaddr_in in;
struct sockaddr_in6 in6;
struct sockaddr_storage storage;
} sockaddr_union_t;
// ...
static avs_error_t stringify_sockaddr_host(const sockaddr_union_t *addr,
char *out_buffer,
size_t out_buffer_size) {
if ((addr->in.sin_family == AF_INET
&& inet_ntop(AF_INET, &addr->in.sin_addr, out_buffer,
(socklen_t) out_buffer_size))
|| (addr->in6.sin6_family == AF_INET6
&& inet_ntop(AF_INET6, &addr->in6.sin6_addr, out_buffer,
(socklen_t) out_buffer_size))) {
return AVS_OK;
}
return avs_errno(AVS_UNKNOWN_ERROR);
}
// ...
static avs_error_t net_remote_host(avs_net_socket_t *sock_,
char *out_buffer,
size_t out_buffer_size) {
net_socket_impl_t *sock = (net_socket_impl_t *) sock_;
sockaddr_union_t addr;
if (getpeername(sock->fd, &addr.addr, &(socklen_t) { sizeof(addr) })) {
return avs_errno(AVS_UNKNOWN_ERROR);
}
return stringify_sockaddr_host(&addr, out_buffer, out_buffer_size);
}
The net_remote_host()
function essentially wraps the POSIX getpeername()
function. However, that function returns a structure from the struct
sockaddr
family, while avs_commons
operates on stringified addresses.
Because several variants of struct sockaddr
may be used, the
sockaddr_union_t
type is declared to accommodate for all supported types.
stringify_sockaddr_host()
function converts the IP address stored in
struct sockaddr_in
or struct sockaddr_in6
into stringified form by
calling POSIX inet_ntop()
.
Note
Out of POSIX APIs, the operations in this tutorial can also be implemented
using getnameinfo()
with NI_NUMERICSERV
and NI_NUMERICHOST
flags
enabled. inet_ntop()
is used here because of broader compatibility.
8.3.1.2.3. Get remote port operation
#include <inttypes.h>
// ...
#include <avsystem/commons/avs_utils.h>
// ...
static avs_error_t stringify_sockaddr_port(const sockaddr_union_t *addr,
char *out_buffer,
size_t out_buffer_size) {
if ((addr->in.sin_family == AF_INET
&& avs_simple_snprintf(out_buffer, out_buffer_size, "%" PRIu16,
ntohs(addr->in.sin_port))
>= 0)
|| (addr->in6.sin6_family == AF_INET6
&& avs_simple_snprintf(out_buffer, out_buffer_size, "%" PRIu16,
ntohs(addr->in6.sin6_port))
>= 0)) {
return AVS_OK;
}
return avs_errno(AVS_UNKNOWN_ERROR);
}
// ...
static avs_error_t net_remote_port(avs_net_socket_t *sock_,
char *out_buffer,
size_t out_buffer_size) {
net_socket_impl_t *sock = (net_socket_impl_t *) sock_;
sockaddr_union_t addr;
if (getpeername(sock->fd, &addr.addr, &(socklen_t) { sizeof(addr) })) {
return avs_errno(AVS_UNKNOWN_ERROR);
}
return stringify_sockaddr_port(&addr, out_buffer, out_buffer_size);
}
Similar to net_remote_host()
, this function also calls getpeername()
-
but its companion stringify_sockaddr_port()
, instead of examining the IP
address stored in the sockaddr
structure, retrieves the port number, and
stringifies it using avs_simple_snprintf()
.
8.3.1.2.4. Update to vtable
Of course the newly implemented function need to be referenced in the virtual method table:
static const avs_net_socket_v_table_t NET_SOCKET_VTABLE = {
.connect = net_connect,
.send = net_send,
.receive = net_receive,
.close = net_close,
.cleanup = net_cleanup,
.get_system_socket = net_system_socket,
.get_remote_host = net_remote_host,
.get_remote_port = net_remote_port,
.get_opt = net_get_opt,
.set_opt = net_set_opt
};