From 1eea53f479c23cb76e0ec4f241c44b79e1feaefc Mon Sep 17 00:00:00 2001 From: Haley Cao Date: Fri, 22 May 2020 19:52:28 +0000 Subject: [PATCH] Added Unix Implementations for Socket Opt Functions Added internal functions and implementations for sockopt functions - Added 4 internal functions: one to retrieve OMR to OS mapping for socket levels, one to retrieve OMR to OS mapping for socket options, two to wrap the code for the socket option functions to reduce clutter. - Added simple implemnentations for the 6 socket options functions. Issue: #5158 Signed-off-by: Haley Cao --- include_core/omrporterror.h | 4 + port/unix/omrsock.c | 148 ++++++++++++++++++++++++++++++++++-- 2 files changed, 146 insertions(+), 6 deletions(-) diff --git a/include_core/omrporterror.h b/include_core/omrporterror.h index 9e5c6cd8def..c2768267b2f 100644 --- a/include_core/omrporterror.h +++ b/include_core/omrporterror.h @@ -335,6 +335,10 @@ #define OMRPORT_ERROR_SOCK_ACCEPT_FAILED (OMRPORT_ERROR_SOCK_BASE - 10) #define OMRPORT_ERROR_SOCK_SEND_FAILED (OMRPORT_ERROR_SOCK_BASE - 11) #define OMRPORT_ERROR_SOCK_RECV_FAILED (OMRPORT_ERROR_SOCK_BASE - 12) +#define OMRPORT_ERROR_SOCK_LEVEL_UNSUPPORTED (OMRPORT_ERROR_SOCK_BASE - 13) +#define OMRPORT_ERROR_SOCK_OPTION_UNSUPPORTED (OMRPORT_ERROR_SOCK_BASE - 14) +#define OMRPORT_ERROR_SOCK_SETSOCKOPT_FAILED (OMRPORT_ERROR_SOCK_BASE - 15) +#define OMRPORT_ERROR_SOCK_GETSOCKOPT_FAILED (OMRPORT_ERROR_SOCK_BASE - 16) /** * @} */ diff --git a/port/unix/omrsock.c b/port/unix/omrsock.c index 4efd7412574..fb2c16496a5 100644 --- a/port/unix/omrsock.c +++ b/port/unix/omrsock.c @@ -188,6 +188,72 @@ get_omr_protocol(int32_t osProtocol) return OMRSOCK_IPPROTO_DEFAULT; } +/** + * @internal Map OMRSOCK API user interface socket level to + * OS socket level. Used to resolve the arguments of socket + * option functions. + * + * Socket Levels currently supported are: + * \arg OMRSOCK_SOL_SOCKET, for most options. + * \arg OMRSOCK_IPPROTO_TCP, for the TCP noDelay option. + * + * @param[in] socketLevel The OMR socket level to be converted. + * + * @return OS protocol on success, or OS_SOL_SOCKET if none exists. + */ +static int32_t +get_os_socket_level(int32_t socketLevel) +{ + switch (socketLevel) + { + case OMRSOCK_SOL_SOCKET: + return OS_SOL_SOCKET; + case OMRSOCK_IPPROTO_TCP: + return OS_SOCK_IPPROTO_TCP; + default: + break; + } + return OMRPORT_ERROR_SOCK_LEVEL_UNSUPPORTED; +} + +/** + * @internal Map OMRSOCK API user interface socket option to OS socket option. + * Used to resolve the arguments of socket option functions. + * Options currently in supported are: + * \arg SO_KEEPALIVE, the keep-alive messages are enabled. + * \arg SO_LINGER, the linger timeout. + * \arg SO_REUSEADDR, the reusage of local address are allowed in bind. + * \arg SO_RCVTIMEO, the receive timeout. + * \arg SO_SNDTIMEO, the send timeout. + * \arg TCP_NODELAY, the buffering scheme disabling Nagle's algorithm. + * + * @param[in] socketOption The portable socket option to convert. + * + * @return OS Socket Option on success, or OS_SOL_SOCKET if none exists. + */ +static int32_t +get_os_socket_option(int32_t socketOption) +{ + switch (socketOption) + { + case OMRSOCK_SO_KEEPALIVE: + return OS_SO_KEEPALIVE; + case OMRSOCK_SO_LINGER: + return OS_SO_LINGER; + case OMRSOCK_SO_REUSEADDR: + return OS_SO_REUSEADDR; + case OMRSOCK_SO_RCVTIMEO: + return OS_SO_RCVTIMEO; + case OMRSOCK_SO_SNDTIMEO: + return OS_SO_SNDTIMEO; + case OMRSOCK_TCP_NODELAY: + return OS_TCP_NODELAY; + default: + break; + } + return OMRPORT_ERROR_SOCK_OPTION_UNSUPPORTED; +} + int32_t omrsock_startup(struct OMRPortLibrary *portLibrary) { @@ -680,38 +746,108 @@ omrsock_linger_init(struct OMRPortLibrary *portLibrary, omrsock_linger_t handle, return 0; } +/** + * @internal Set socket options for all option value types, since pointers to option values are casted to void types. + * + * @param portLibrary The port library. + * @param sock Pointer to the socket to set the option in. + * @param optlevel The level within the IP stack at which the option is defined. + * @param optname The name of the option to set. + * @param optval Void type pointer to the option value to update the socket option with. + * @param len Length of the option value. + * + * @return 0, if no errors occurred, otherwise return an error. + */ +int32_t +set_opt(struct OMRPortLibrary *portLibrary, omr_os_socket sock, int32_t optlevel, int32_t optname, void *optval, socklen_t len) +{ + int32_t osLevel = get_os_socket_level(optlevel); + int32_t osOption = get_os_socket_option(optname); + + if (osLevel == OMRPORT_ERROR_SOCK_LEVEL_UNSUPPORTED) { + return OMRPORT_ERROR_SOCK_LEVEL_UNSUPPORTED; + } + + if (osOption == OMRPORT_ERROR_SOCK_OPTION_UNSUPPORTED) { + return OMRPORT_ERROR_SOCK_OPTION_UNSUPPORTED; + } + + if (0 != setsockopt(sock, osLevel, osOption, optval, len)) { + portLibrary->error_set_last_error(portLibrary, errno, OMRPORT_ERROR_SOCK_SETSOCKOPT_FAILED); + return OMRPORT_ERROR_SOCK_SETSOCKOPT_FAILED; + } + + return 0; +} + +/** + * @internal Get socket options for all option value types, since pointers to option values are casted to void types. + * Opposite of @ref set_opt. + * + * @param portLibrary The port library. + * @param sock Pointer to the socket to query for the option value. + * @param optlevel The level within the IP stack at which the option is defined. + * @param optname The name of the option to retrieve. + * @param optval Void type pointer to the pre-allocated space to update with the option value. + * @param len Length of the option value. + * + * @return 0, if no errors occurred, otherwise return an error. + */ +int32_t +get_opt(struct OMRPortLibrary *portLibrary, omr_os_socket sock, int32_t optlevel, int32_t optname, void *optval, socklen_t len) +{ + int32_t osLevel = get_os_socket_level(optlevel); + int32_t osOption = get_os_socket_option(optname); + socklen_t optlen = len; + + if (osLevel == OMRPORT_ERROR_SOCK_LEVEL_UNSUPPORTED) { + return OMRPORT_ERROR_SOCK_LEVEL_UNSUPPORTED; + } + + if (osOption == OMRPORT_ERROR_SOCK_OPTION_UNSUPPORTED) { + return OMRPORT_ERROR_SOCK_OPTION_UNSUPPORTED; + } + + if (0 != getsockopt(sock, osLevel, osOption, optval, &optlen)) { + portLibrary->error_set_last_error(portLibrary, errno, OMRPORT_ERROR_SOCK_GETSOCKOPT_FAILED); + return OMRPORT_ERROR_SOCK_GETSOCKOPT_FAILED; + } + + return 0; +} + int32_t omrsock_setsockopt_int(struct OMRPortLibrary *portLibrary, omrsock_socket_t handle, int32_t optlevel, int32_t optname, int32_t *optval) { - return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM; + return set_opt(portLibrary, handle->data, optlevel, optname, (void*)optval, sizeof(int32_t)); } int32_t omrsock_setsockopt_linger(struct OMRPortLibrary *portLibrary, omrsock_socket_t handle, int32_t optlevel, int32_t optname, omrsock_linger_t optval) { - return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM; + return set_opt(portLibrary, handle->data, optlevel, optname, (void*)&optval->data, sizeof(struct linger)); } int32_t omrsock_setsockopt_timeval(struct OMRPortLibrary *portLibrary, omrsock_socket_t handle, int32_t optlevel, int32_t optname, omrsock_timeval_t optval) { - return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM; + return set_opt(portLibrary, handle->data, optlevel, optname, (void*)&optval->data, sizeof(struct timeval)); } int32_t omrsock_getsockopt_int(struct OMRPortLibrary *portLibrary, omrsock_socket_t handle, int32_t optlevel, int32_t optname, int32_t *optval) { - return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM; + return get_opt(portLibrary, handle->data, optlevel, optname, (void*)optval, sizeof(int32_t)); } int32_t omrsock_getsockopt_linger(struct OMRPortLibrary *portLibrary, omrsock_socket_t handle, int32_t optlevel, int32_t optname, omrsock_linger_t optval) { - return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM; + return get_opt(portLibrary, handle->data, optlevel, optname, (void*)&optval->data, sizeof(struct linger)); } int32_t omrsock_getsockopt_timeval(struct OMRPortLibrary *portLibrary, omrsock_socket_t handle, int32_t optlevel, int32_t optname, omrsock_timeval_t optval) { - return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM; + return get_opt(portLibrary, handle->data, optlevel, optname, (void*)&optval->data, sizeof(struct timeval)); }