From ec30aa75910e2fd77c74336a92923f9c8ad7e6f9 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Wed, 6 Mar 2024 16:55:16 -0500 Subject: [PATCH 1/5] Fix #1455, High-resolution timed ops Add API calls equivalent to existing calls that use an absolute timeout as opposed to a relative timeout. The absolute timeout can support resolution of 0.1 usec in the default configuration. Internally this primarily affects the underlying call to select(). Note that per the definition of select() in POSIX, it uses a "struct timeval" which has a resolution of 1 usec. --- src/os/inc/osapi-clock.h | 108 +++++++++++++++++ src/os/inc/osapi-file.h | 81 ++++++++++++- src/os/inc/osapi-select.h | 94 +++++++++++++++ src/os/inc/osapi-sockets.h | 106 ++++++++++++++++- src/os/portable/os-impl-bsd-select.c | 73 +++++------- src/os/portable/os-impl-bsd-sockets.c | 16 +-- src/os/portable/os-impl-no-sockets.c | 6 +- src/os/portable/os-impl-posix-io.c | 8 +- src/os/shared/inc/os-shared-file.h | 4 +- src/os/shared/inc/os-shared-select.h | 5 +- src/os/shared/inc/os-shared-sockets.h | 6 +- src/os/shared/src/osapi-clock.c | 80 +++++++++++++ src/os/shared/src/osapi-file.c | 30 ++++- src/os/shared/src/osapi-select.c | 30 ++++- src/os/shared/src/osapi-sockets.c | 46 +++++++- src/tests/network-api-test/network-api-test.c | 2 + .../portable/src/coveragetest-bsd-select.c | 111 ++++++++---------- .../portable/src/coveragetest-bsd-sockets.c | 44 +++---- .../portable/src/coveragetest-no-sockets.c | 6 +- .../portable/src/coveragetest-posix-io.c | 24 ++-- .../shared/src/coveragetest-clock.c | 27 +++++ .../ut-stubs/CMakeLists.txt | 4 +- .../src/os-shared-clock-impl-handlers.c | 52 ++++++++ .../ut-stubs/src/os-shared-clock-impl-stubs.c | 4 +- .../ut-stubs/src/os-shared-file-impl-stubs.c | 8 +- .../src/os-shared-select-impl-stubs.c | 8 +- .../src/os-shared-sockets-impl-stubs.c | 12 +- src/ut-stubs/osapi-clock-stubs.c | 32 +++++ src/ut-stubs/osapi-file-stubs.c | 38 ++++++ src/ut-stubs/osapi-sockets-stubs.c | 21 ++++ 30 files changed, 893 insertions(+), 193 deletions(-) create mode 100644 src/unit-test-coverage/ut-stubs/src/os-shared-clock-impl-handlers.c diff --git a/src/os/inc/osapi-clock.h b/src/os/inc/osapi-clock.h index 50cc82c6d..e21e34f90 100644 --- a/src/os/inc/osapi-clock.h +++ b/src/os/inc/osapi-clock.h @@ -47,6 +47,29 @@ typedef struct int64 ticks; /**< Ticks elapsed since reference point */ } OS_time_t; +/** + * @brief The maximum value for OS_time_t + * + * This is the largest positive (future) time that is representable + * in an OS_time_t value. + */ +#define OS_TIME_MAX ((OS_time_t) {INT64_MAX}) + +/** + * @brief The zero value for OS_time_t + * + * This is a reasonable initializer/placeholder value for an OS_time_t + */ +#define OS_TIME_ZERO ((OS_time_t) {0}) + +/** + * @brief The minimum value for OS_time_t + * + * This is the largest negative (past) time that is representable + * in an OS_time_t value. + */ +#define OS_TIME_MIN ((OS_time_t) {INT64_MIN}) + /** * @brief Multipliers/divisors to convert ticks into standardized units * @@ -102,6 +125,45 @@ int32 OS_GetLocalTime(OS_time_t *time_struct); */ int32 OS_SetLocalTime(const OS_time_t *time_struct); +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Gets an absolute time value relative to the current time + * + * This function adds the given interval, expressed in milliseconds, to the + * current clock and returns the result. + * + * @note This is intended to ease transitioning from a relative timeout value to + * and absolute timeout value. The result can be passed to any function + * that accepts an absolute timeout, to mimic the behavior of a relative timeout. + * + * @param[in] relative_msec A relative time interval, in milliseconds + * + * @returns Absolute time value after adding interval + */ +OS_time_t OS_TimeFromRelativeMilliseconds(int32 relative_msec); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Gets a relative time value from an absolute time + * + * This function computes the number of milliseconds until the given + * absolute time value is reached in the system clock. + * + * @note This is intended to ease transitioning from a relative timeout value to + * and absolute timeout value. The result can be passed to any function + * that accepts a relative timeout, to mimic the behavior of an absolute timeout. + * + * The return value of this function is intended to be compatible with the relative + * timeout parameter of various OSAL APIs e.g. OS_TimedRead() / OS_TimedWrite() + * + * @param[in] time An absolute time value + * + * @returns Milliseconds until time value will be reached + * @retval OS_CHECK (0) if time is the current time or is in the past + * @retval OS_PEND (-1) if time is far in the future (not expressable as an int32) + */ +int32 OS_TimeToRelativeMilliseconds(OS_time_t time); + /*-------------------------------------------------------------------------------------*/ /* * Accessor / Unit Conversion routines for OS_time_t @@ -485,6 +547,52 @@ static inline OS_time_t OS_TimeSubtract(OS_time_t time1, OS_time_t time2) return ostm; } +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Checks if two time values are equal + * + * @param[in] time1 The first time value + * @param[in] time2 The second time value + * + * @retval true if the two values are equal + * @retval false if the two values are not equal + */ +static inline bool OS_TimeEqual(OS_time_t time1, OS_time_t time2) +{ + return (time1.ticks == time2.ticks); +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Checks the sign of the time value + * + * @param[in] time The time to check + * + * @retval -1 if the time value is negative / below 0 + * @retval 0 if the time value is 0 + * @retval 1 if the time value is positive / above 0 + */ +static inline int8_t OS_TimeGetSign(OS_time_t time) +{ + return (time.ticks > 0) - (time.ticks < 0); +} + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Compares two time values + * + * @param[in] time1 The first time + * @param[in] time2 The second time + * + * @retval -1 if the time1 < time2 + * @retval 0 if the times are equal + * @retval 1 if the time1 > time2 + */ +static inline int8_t OS_TimeCompare(OS_time_t time1, OS_time_t time2) +{ + return OS_TimeGetSign(OS_TimeSubtract(time1, time2)); +} + /**@}*/ #endif /* OSAPI_CLOCK_H */ diff --git a/src/os/inc/osapi-file.h b/src/os/inc/osapi-file.h index e039f2bfc..59c4bf359 100644 --- a/src/os/inc/osapi-file.h +++ b/src/os/inc/osapi-file.h @@ -237,7 +237,49 @@ int32 OS_write(osal_id_t filedes, const void *buffer, size_t nbytes); * @param[in] filedes The handle ID to operate on * @param[out] buffer Storage location for file data @nonnull * @param[in] nbytes Maximum number of bytes to read @nonzero - * @param[in] timeout Maximum time to wait, in milliseconds (OS_PEND = forever) + * @param[in] abstime Absolute time at which this function should return, if no data is readable + * + * @returns Byte count on success or appropriate error code, see @ref OSReturnCodes + * @retval #OS_ERROR_TIMEOUT if no data became available during timeout period + * @retval #OS_ERR_INVALID_ID if the file descriptor passed in is invalid + * @retval #OS_ERR_INVALID_SIZE if the passed-in size is not valid + * @retval #OS_INVALID_POINTER if the passed-in buffer is not valid + * @retval 0 if at end of file/stream data + */ +int32 OS_TimedReadAbs(osal_id_t filedes, void *buffer, size_t nbytes, OS_time_t abstime); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief File/Stream input read with a timeout + * + * This implements a time-limited read and is primarily intended for use with + * sockets but may also work with any other stream-like resource that the underlying + * OS supports, such as pipes or special devices. + * + * If data is immediately available on the file/socket, this will return that data + * along with the actual number of bytes that were immediately available. It will + * not block. + * + * If the file position is at the end of file or end of stream data (e.g. if the remote + * end has closed the connection), then this function will immediately return 0 without + * blocking for the timeout period. + * + * If no data is immediately available, but the underlying resource/stream is still + * connected to a peer, this will wait up to the given timeout for additional + * data to appear. If no data appears within the timeout period, then this returns + * the #OS_ERROR_TIMEOUT status code. This allows the caller to differentiate + * an open (but idle) socket connection from a connection which has been closed + * by the remote peer. + * + * In all cases this will return successfully as soon as at least 1 byte of actual + * data is available. It will not attempt to read the entire input buffer. + * + * If an EOF condition occurs prior to timeout, this function returns zero. + * + * @param[in] filedes The handle ID to operate on + * @param[out] buffer Storage location for file data @nonnull + * @param[in] nbytes Maximum number of bytes to read @nonzero + * @param[in] timeout Maximum time to wait, in milliseconds, relative to current time (OS_PEND = forever) * * @returns Byte count on success or appropriate error code, see @ref OSReturnCodes * @retval #OS_ERROR_TIMEOUT if no data became available during timeout period @@ -272,7 +314,42 @@ int32 OS_TimedRead(osal_id_t filedes, void *buffer, size_t nbytes, int32 timeout * @param[in] filedes The handle ID to operate on * @param[in] buffer Source location for file data @nonnull * @param[in] nbytes Maximum number of bytes to read @nonzero - * @param[in] timeout Maximum time to wait, in milliseconds (OS_PEND = forever) + * @param[in] abstime Absolute time at which this function should return, if no data is readable + * + * @return A non-negative byte count or appropriate error code, see @ref OSReturnCodes + * @retval #OS_ERROR_TIMEOUT if no data became available during timeout period + * @retval #OS_ERR_INVALID_ID if the file descriptor passed in is invalid + * @retval #OS_ERR_INVALID_SIZE if the passed-in size is not valid + * @retval #OS_INVALID_POINTER if the passed-in buffer is not valid + * @retval 0 if file/stream cannot accept any more data + */ +int32 OS_TimedWriteAbs(osal_id_t filedes, const void *buffer, size_t nbytes, OS_time_t abstime); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief File/Stream output write with a timeout + * + * This implements a time-limited write and is primarily intended for use with + * sockets but may also work with any other stream-like resource that the underlying + * OS supports. + * + * If output buffer space is immediately available on the file/socket, this will + * place data into the buffer and return the actual number of bytes that were + * queued for output. It will not block. + * + * If no output buffer space is immediately available, this will wait up to the + * given timeout for space to become available. If no space becomes available within + * the timeout period, then this returns an error code (not zero). + * + * In all cases this will return successfully as soon as at least 1 byte of actual + * data is output. It will _not_ attempt to write the entire output buffer. + * + * If an EOF condition occurs prior to timeout, this function returns zero. + * + * @param[in] filedes The handle ID to operate on + * @param[in] buffer Source location for file data @nonnull + * @param[in] nbytes Maximum number of bytes to read @nonzero + * @param[in] timeout Maximum time to wait, in milliseconds, relative to current time (OS_PEND = forever) * * @return A non-negative byte count or appropriate error code, see @ref OSReturnCodes * @retval #OS_ERROR_TIMEOUT if no data became available during timeout period diff --git a/src/os/inc/osapi-select.h b/src/os/inc/osapi-select.h index 20214c9f7..abaf0d397 100644 --- a/src/os/inc/osapi-select.h +++ b/src/os/inc/osapi-select.h @@ -27,6 +27,7 @@ #include "osconfig.h" #include "common_types.h" +#include "osapi-clock.h" /** * @brief An abstract structure capable of holding several OSAL IDs @@ -83,6 +84,52 @@ typedef enum * If the timeout occurs this returns an error code and all output sets * should be empty. * + * This API is identical to OS_SelectMultiple() except for the timeout parameter. In + * this call, timeout is expressed as an absolute value of the OS clock, in the same + * time domain as obtained via OS_GetLocalTime(). This allows for a more precise + * timeout than what is possible via the normal OS_SelectMultiple(). + * + * @note This does not lock or otherwise protect the file handles in the + * given sets. If a filehandle supplied via one of the FdSet arguments + * is closed or modified by another while this function is in progress, + * the results are undefined. Because of this limitation, it is recommended + * to use OS_SelectSingle() whenever possible. + * + * @param[in,out] ReadSet Set of handles to check/wait to become readable + * @param[in,out] WriteSet Set of handles to check/wait to become writable + * @param[in] abs_timeout The absolute time that the call may block until + * + * @sa OS_SelectMultiple() + * + * @return Execution status, see @ref OSReturnCodes + * @retval #OS_SUCCESS If any handle in the ReadSet or WriteSet is readable or writable, respectively + * @retval #OS_ERROR_TIMEOUT If no handles in the ReadSet or WriteSet became readable or writable within the timeout + * @retval #OS_ERR_OPERATION_NOT_SUPPORTED if a specified handle does not support select + * @retval #OS_ERR_INVALID_ID if no valid handles were contained in the ReadSet/WriteSet + */ +int32 OS_SelectMultipleAbs(OS_FdSet *ReadSet, OS_FdSet *WriteSet, OS_time_t abs_timeout); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Wait for events across multiple file handles + * + * Wait for any of the given sets of IDs to become readable or writable + * + * This function will block until any of the following occurs: + * - At least one OSAL ID in the ReadSet is readable + * - At least one OSAL ID in the WriteSet is writable + * - The timeout has elapsed + * + * The sets are input/output parameters. On entry, these indicate the + * file handle(s) to wait for. On exit, these are set to the actual + * file handle(s) that have activity. + * + * If the timeout occurs this returns an error code and all output sets + * should be empty. + * + * The timeout is expressed in milliseconds, relative to the time that the API was + * invoked. Use OS_SelectMultipleAbs() for higher timing precision. + * * @note This does not lock or otherwise protect the file handles in the * given sets. If a filehandle supplied via one of the FdSet arguments * is closed or modified by another while this function is in progress, @@ -94,6 +141,8 @@ typedef enum * @param[in] msecs Indicates the timeout. Positive values will wait up to that many milliseconds. Zero will not wait * (poll). Negative values will wait forever (pend) * + * @sa OS_SelectMultipleAbs() + * * @return Execution status, see @ref OSReturnCodes * @retval #OS_SUCCESS If any handle in the ReadSet or WriteSet is readable or writable, respectively * @retval #OS_ERROR_TIMEOUT If no handles in the ReadSet or WriteSet became readable or writable within the timeout @@ -123,11 +172,56 @@ int32 OS_SelectMultiple(OS_FdSet *ReadSet, OS_FdSet *WriteSet, int32 msecs); * To mitigate this risk the application may prefer to use * the OS_TimedRead/OS_TimedWrite calls. * + * This API is identical to OS_SelectSingle() except for the timeout parameter. In + * this call, timeout is expressed as an absolute value of the OS clock, in the same + * time domain as obtained via OS_GetLocalTime(). This allows for a more precise + * timeout than what is possible via the normal OS_SelectSingle(). + * + * @param[in] objid The handle ID to select on + * @param[in,out] StateFlags State flag(s) (readable or writable) @nonnull + * @param[in] abs_timeout The absolute time that the call may block until + * + * @sa OS_SelectSingle() + * + * @return Execution status, see @ref OSReturnCodes + * @retval #OS_SUCCESS If the handle is readable and/or writable, as requested + * @retval #OS_ERROR_TIMEOUT If the handle did not become readable or writable within the timeout + * @retval #OS_INVALID_POINTER if argument is NULL + * @retval #OS_ERR_INVALID_ID if the objid is not a valid handle + */ +int32 OS_SelectSingleAbs(osal_id_t objid, uint32 *StateFlags, OS_time_t abs_timeout); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Wait for events on a single file handle + * + * Wait for a single OSAL filehandle to change state + * + * This function can be used to wait for a single OSAL stream ID + * to become readable or writable. On entry, the "StateFlags" + * parameter should be set to the desired state (OS_STREAM_STATE_READABLE + * and/or OS_STREAM_STATE_WRITABLE) and upon return the flags + * will be set to the state actually detected. + * + * As this operates on a single ID, the filehandle is protected + * during this call, such that another thread accessing the same + * handle will return an error. However, it is important to note that + * once the call returns then other threads may then also read/write + * and affect the state before the current thread can service it. + * + * To mitigate this risk the application may prefer to use + * the OS_TimedRead/OS_TimedWrite calls. + * + * The timeout is expressed in milliseconds, relative to the time that the API was + * invoked. Use OS_SelectSingleAbs() for higher timing precision. + * * @param[in] objid The handle ID to select on * @param[in,out] StateFlags State flag(s) (readable or writable) @nonnull * @param[in] msecs Indicates the timeout. Positive values will wait up to that many milliseconds. Zero will not wait * (poll). Negative values will wait forever (pend) * + * @sa OS_SelectSingleAbs() + * * @return Execution status, see @ref OSReturnCodes * @retval #OS_SUCCESS If the handle is readable and/or writable, as requested * @retval #OS_ERROR_TIMEOUT If the handle did not become readable or writable within the timeout diff --git a/src/os/inc/osapi-sockets.h b/src/os/inc/osapi-sockets.h index 93d046527..5a4dd3e6f 100644 --- a/src/os/inc/osapi-sockets.h +++ b/src/os/inc/osapi-sockets.h @@ -28,6 +28,7 @@ /* NOTE - osconfig.h may optionally specify the value for OS_SOCADDR_MAX_LEN */ #include "osconfig.h" #include "common_types.h" +#include "osapi-clock.h" /* * The absolute maximum size of a network address @@ -343,10 +344,43 @@ int32 OS_SocketBindAddress(osal_id_t sock_id, const OS_SockAddr_t *Addr); * This only applies to stream-oriented sockets. Calling this on a datagram * socket will return an error (these sockets should use SendTo/RecvFrom). * + * This API is identical to OS_SocketConnect() except for the timeout parameter. In + * this call, timeout is expressed as an absolute value of the OS clock, in the same + * time domain as obtained via OS_GetLocalTime(). This allows for a more precise + * timeout than what is possible via the normal OS_SocketConnect(). + * + * @param[in] sock_id The socket ID + * @param[in] Addr The remote address to connect to @nonnull + * @param[in] abs_timeout The absolute time that the call may block until + * + * @sa OS_SocketConnect() + * + * @return Execution status, see @ref OSReturnCodes + * @retval #OS_SUCCESS @copybrief OS_SUCCESS + * @retval #OS_ERR_INCORRECT_OBJ_STATE if the socket is already connected + * @retval #OS_ERR_INVALID_ID if the sock_id parameter is not valid + * @retval #OS_ERR_INCORRECT_OBJ_TYPE if the handle is not a socket + * @retval #OS_INVALID_POINTER if Addr argument is NULL + */ +int32 OS_SocketConnectAbs(osal_id_t sock_id, const OS_SockAddr_t *Addr, OS_time_t abs_timeout); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Connects a socket to a given remote address. + * + * The socket will be connected to the remote address and port, if available. + * This only applies to stream-oriented sockets. Calling this on a datagram + * socket will return an error (these sockets should use SendTo/RecvFrom). + * + * The timeout is expressed in milliseconds, relative to the time that the API was + * invoked. Use OS_SocketConnectAbs() for higher timing precision. + * * @param[in] sock_id The socket ID * @param[in] Addr The remote address to connect to @nonnull * @param[in] timeout The maximum amount of time to wait, or OS_PEND to wait forever * + * @sa OS_SocketConnectAbs() + * * @return Execution status, see @ref OSReturnCodes * @retval #OS_SUCCESS @copybrief OS_SUCCESS * @retval #OS_ERR_INCORRECT_OBJ_STATE if the socket is already connected @@ -387,11 +421,49 @@ int32 OS_SocketShutdown(osal_id_t sock_id, OS_SocketShutdownMode_t Mode); * The new stream connection is then returned to the caller and the original * server socket ID can be reused for the next connection. * + * This API is identical to OS_SocketAccept() except for the timeout parameter. In + * this call, timeout is expressed as an absolute value of the OS clock, in the same + * time domain as obtained via OS_GetLocalTime(). This allows for a more precise + * timeout than what is possible via the normal OS_SocketAccept(). + * + * @param[in] sock_id The server socket ID, previously bound using OS_SocketBind() + * @param[out] connsock_id The connection socket, a new ID that can be read/written @nonnull + * @param[in] Addr The remote address of the incoming connection @nonnull + * @param[in] abs_timeout The absolute time that the call may block until + * + * @sa OS_SocketAccept() + * + * @return Execution status, see @ref OSReturnCodes + * @retval #OS_SUCCESS @copybrief OS_SUCCESS + * @retval #OS_INVALID_POINTER if argument is NULL + * @retval #OS_ERR_INVALID_ID if the sock_id parameter is not valid + * @retval #OS_ERR_INCORRECT_OBJ_TYPE if the handle is not a socket + * @retval #OS_ERR_INCORRECT_OBJ_STATE if the socket is not bound or already connected + */ +int32 OS_SocketAcceptAbs(osal_id_t sock_id, osal_id_t *connsock_id, OS_SockAddr_t *Addr, OS_time_t abs_timeout); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Waits for and accept the next incoming connection on the given socket + * + * This is used for sockets operating in a "server" role. The socket must be + * a stream type (connection-oriented) and previously bound to a local address + * using OS_SocketBind(). This will block the caller up to the given timeout + * or until an incoming connection request occurs, whichever happens first. + * + * The new stream connection is then returned to the caller and the original + * server socket ID can be reused for the next connection. + * + * The timeout is expressed in milliseconds, relative to the time that the API was + * invoked. Use OS_SocketAcceptAbs() for higher timing precision. + * * @param[in] sock_id The server socket ID, previously bound using OS_SocketBind() * @param[out] connsock_id The connection socket, a new ID that can be read/written @nonnull * @param[in] Addr The remote address of the incoming connection @nonnull * @param[in] timeout The maximum amount of time to wait, or OS_PEND to wait forever * + * @sa OS_SocketAcceptAbs() + * * @return Execution status, see @ref OSReturnCodes * @retval #OS_SUCCESS @copybrief OS_SUCCESS * @retval #OS_INVALID_POINTER if argument is NULL @@ -408,11 +480,43 @@ int32 OS_SocketAccept(osal_id_t sock_id, osal_id_t *connsock_id, OS_SockAddr_t * * If a message is already available on the socket, this should immediately return * that data without blocking. Otherwise, it may block up to the given timeout. * + * This API is identical to OS_SocketRecvFrom() except for the timeout parameter. In + * this call, timeout is expressed as an absolute value of the OS clock, in the same + * time domain as obtained via OS_GetLocalTime(). This allows for a more precise + * timeout than what is possible via the normal OS_SocketRecvFrom(). + * * @param[in] sock_id The socket ID, previously bound using OS_SocketBind() * @param[out] buffer Pointer to message data receive buffer @nonnull * @param[in] buflen The maximum length of the message data to receive @nonzero * @param[out] RemoteAddr Buffer to store the remote network address (may be NULL) - * @param[in] timeout The maximum amount of time to wait, or OS_PEND to wait forever + * @param[in] abs_timeout The absolute time at which the call should return if nothing received + * + * @return Count of actual bytes received or error status, see @ref OSReturnCodes + * @retval #OS_INVALID_POINTER if argument is NULL + * @retval #OS_ERR_INVALID_SIZE if passed-in buflen is not valid + * @retval #OS_ERR_INVALID_ID if the sock_id parameter is not valid + * @retval #OS_ERR_INCORRECT_OBJ_TYPE if the handle is not a socket + */ +int32 OS_SocketRecvFromAbs(osal_id_t sock_id, void *buffer, size_t buflen, OS_SockAddr_t *RemoteAddr, + OS_time_t abs_timeout); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Reads data from a message-oriented (datagram) socket + * + * If a message is already available on the socket, this should immediately return + * that data without blocking. Otherwise, it may block up to the given timeout. + * + * The timeout is expressed in milliseconds, relative to the time that the API was + * invoked. Use OS_SocketRecvFromAbs() for higher timing precision. + * + * @param[in] sock_id The socket ID, previously bound using OS_SocketBind() + * @param[out] buffer Pointer to message data receive buffer @nonnull + * @param[in] buflen The maximum length of the message data to receive @nonzero + * @param[out] RemoteAddr Buffer to store the remote network address (may be NULL) + * @param[in] timeout The maximum amount of time to wait or OS_PEND to wait forever + * + * @sa OS_SocketRecvFromAbs() * * @return Count of actual bytes received or error status, see @ref OSReturnCodes * @retval #OS_INVALID_POINTER if argument is NULL diff --git a/src/os/portable/os-impl-bsd-select.c b/src/os/portable/os-impl-bsd-select.c index baa516797..162909b04 100644 --- a/src/os/portable/os-impl-bsd-select.c +++ b/src/os/portable/os-impl-bsd-select.c @@ -41,6 +41,7 @@ #include #include "os-impl-select.h" +#include "os-shared-clock.h" #include "os-shared-select.h" #include "os-shared-idmap.h" @@ -163,68 +164,52 @@ static void OS_FdSet_ConvertOut_Impl(fd_set *OS_set, OS_FdSet *OSAL_set) * Actual implementation of select() call * Used by SelectSingle and SelectMultiple implementations (below) *-----------------------------------------------------------------*/ -static int32 OS_DoSelect(int maxfd, fd_set *rd_set, fd_set *wr_set, int32 msecs) +static int32 OS_DoSelect(int maxfd, fd_set *rd_set, fd_set *wr_set, OS_time_t abs_timeout) { int os_status; int32 return_code; struct timeval tv; struct timeval *tvptr; - struct timespec ts_now; - struct timespec ts_end; + OS_time_t curr_time; - if (msecs > 0) + /* Implementations may pass OS_TIME_MAX to mean wait forever */ + if (OS_TimeEqual(abs_timeout, OS_TIME_MAX)) { - clock_gettime(CLOCK_MONOTONIC, &ts_now); - ts_end.tv_sec = ts_now.tv_sec + (msecs / 1000); - ts_end.tv_nsec = ts_now.tv_nsec + (1000000 * (msecs % 1000)); - if (ts_end.tv_nsec >= 1000000000) - { - ++ts_end.tv_sec; - ts_end.tv_nsec -= 1000000000; - } + tvptr = NULL; } else { - /* Zero for consistency and to avoid possible confusion if not cleared */ - memset(&ts_end, 0, sizeof(ts_end)); + /* Not waiting forever, some form of timeout will be calculated */ + tvptr = &tv; } + curr_time = abs_timeout; + do { - if (msecs < 0) - { - tvptr = NULL; - } - else if (msecs == 0) - { - tvptr = &tv; - tv.tv_sec = 0; - tv.tv_usec = 0; - } - else + if (tvptr != NULL) { - tvptr = &tv; - - clock_gettime(CLOCK_MONOTONIC, &ts_now); - - /* note that the tv_sec and tv_usec/tv_nsec values are all signed longs, so OK to subtract */ - tv.tv_sec = ts_end.tv_sec - ts_now.tv_sec; - tv.tv_usec = (ts_end.tv_nsec - ts_now.tv_nsec) / 1000; - - if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec < 0)) + if (OS_TimeGetSign(abs_timeout) > 0) { - os_status = 0; - break; + OS_GetLocalTime_Impl(&curr_time); + curr_time = OS_TimeSubtract(abs_timeout, curr_time); } - - if (tv.tv_usec < 0) + if (OS_TimeGetSign(curr_time) <= 0) { - tv.tv_usec += 1000000; - --tv.tv_sec; + /* timeout has already passed - this will still poll, but not block */ + tv.tv_sec = 0; + tv.tv_usec = 0; + } + else + { + /* timeout is in the future */ + tv.tv_sec = OS_TimeGetTotalSeconds(curr_time); + tv.tv_usec = OS_TimeGetMicrosecondsPart(curr_time); } } os_status = select(maxfd + 1, rd_set, wr_set, NULL, tvptr); + } while (os_status < 0 && (errno == EINTR || errno == EAGAIN)); if (os_status < 0) @@ -253,7 +238,7 @@ static int32 OS_DoSelect(int maxfd, fd_set *rd_set, fd_set *wr_set, int32 msecs) * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_SelectSingle_Impl(const OS_object_token_t *token, uint32 *SelectFlags, int32 msecs) +int32 OS_SelectSingle_Impl(const OS_object_token_t *token, uint32 *SelectFlags, OS_time_t abs_timeout) { int32 return_code; fd_set wr_set; @@ -290,7 +275,7 @@ int32 OS_SelectSingle_Impl(const OS_object_token_t *token, uint32 *SelectFlags, FD_SET(impl->fd, &wr_set); } - return_code = OS_DoSelect(impl->fd, &rd_set, &wr_set, msecs); + return_code = OS_DoSelect(impl->fd, &rd_set, &wr_set, abs_timeout); if (return_code == OS_SUCCESS) { @@ -323,7 +308,7 @@ int32 OS_SelectSingle_Impl(const OS_object_token_t *token, uint32 *SelectFlags, * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_SelectMultiple_Impl(OS_FdSet *ReadSet, OS_FdSet *WriteSet, int32 msecs) +int32 OS_SelectMultiple_Impl(OS_FdSet *ReadSet, OS_FdSet *WriteSet, OS_time_t abs_timeout) { fd_set wr_set; fd_set rd_set; @@ -352,7 +337,7 @@ int32 OS_SelectMultiple_Impl(OS_FdSet *ReadSet, OS_FdSet *WriteSet, int32 msecs) if (maxfd >= 0) { - return_code = OS_DoSelect(maxfd, &rd_set, &wr_set, msecs); + return_code = OS_DoSelect(maxfd, &rd_set, &wr_set, abs_timeout); } else { diff --git a/src/os/portable/os-impl-bsd-sockets.c b/src/os/portable/os-impl-bsd-sockets.c index de03b270a..3102d0aac 100644 --- a/src/os/portable/os-impl-bsd-sockets.c +++ b/src/os/portable/os-impl-bsd-sockets.c @@ -52,6 +52,7 @@ #include #include "os-impl-sockets.h" +#include "os-shared-clock.h" #include "os-shared-file.h" #include "os-shared-select.h" #include "os-shared-sockets.h" @@ -284,7 +285,7 @@ int32 OS_SocketListen_Impl(const OS_object_token_t *token) * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_SocketConnect_Impl(const OS_object_token_t *token, const OS_SockAddr_t *Addr, int32 timeout) +int32 OS_SocketConnect_Impl(const OS_object_token_t *token, const OS_SockAddr_t *Addr, OS_time_t abs_timeout) { int32 return_code; int os_status; @@ -345,7 +346,7 @@ int32 OS_SocketConnect_Impl(const OS_object_token_t *token, const OS_SockAddr_t operation = OS_STREAM_STATE_WRITABLE; if (impl->selectable) { - return_code = OS_SelectSingle_Impl(token, &operation, timeout); + return_code = OS_SelectSingle_Impl(token, &operation, abs_timeout); } if (return_code == OS_SUCCESS) { @@ -422,7 +423,7 @@ int32 OS_SocketShutdown_Impl(const OS_object_token_t *token, OS_SocketShutdownMo * *-----------------------------------------------------------------*/ int32 OS_SocketAccept_Impl(const OS_object_token_t *sock_token, const OS_object_token_t *conn_token, - OS_SockAddr_t *Addr, int32 timeout) + OS_SockAddr_t *Addr, OS_time_t abs_timeout) { int32 return_code; uint32 operation; @@ -436,7 +437,7 @@ int32 OS_SocketAccept_Impl(const OS_object_token_t *sock_token, const OS_object_ operation = OS_STREAM_STATE_READABLE; if (sock_impl->selectable) { - return_code = OS_SelectSingle_Impl(sock_token, &operation, timeout); + return_code = OS_SelectSingle_Impl(sock_token, &operation, abs_timeout); } else { @@ -476,7 +477,7 @@ int32 OS_SocketAccept_Impl(const OS_object_token_t *sock_token, const OS_object_ * *-----------------------------------------------------------------*/ int32 OS_SocketRecvFrom_Impl(const OS_object_token_t *token, void *buffer, size_t buflen, OS_SockAddr_t *RemoteAddr, - int32 timeout) + OS_time_t abs_timeout) { int32 return_code; int os_result; @@ -507,11 +508,12 @@ int32 OS_SocketRecvFrom_Impl(const OS_object_token_t *token, void *buffer, size_ if (impl->selectable) { waitflags = MSG_DONTWAIT; - return_code = OS_SelectSingle_Impl(token, &operation, timeout); + return_code = OS_SelectSingle_Impl(token, &operation, abs_timeout); } else { - if (timeout == 0) + /* This is a backup option - check if the abs timeout would be a poll/check op */ + if (OS_TimeToRelativeMilliseconds(abs_timeout) == OS_CHECK) { waitflags = MSG_DONTWAIT; } diff --git a/src/os/portable/os-impl-no-sockets.c b/src/os/portable/os-impl-no-sockets.c index 0d14700d2..3c7f15f23 100644 --- a/src/os/portable/os-impl-no-sockets.c +++ b/src/os/portable/os-impl-no-sockets.c @@ -74,7 +74,7 @@ int32 OS_SocketListen_Impl(const OS_object_token_t *token) * * See prototype for argument/return detail *-----------------------------------------------------------------*/ -int32 OS_SocketConnect_Impl(const OS_object_token_t *token, const OS_SockAddr_t *Addr, int32 timeout) +int32 OS_SocketConnect_Impl(const OS_object_token_t *token, const OS_SockAddr_t *Addr, OS_time_t abs_timeout) { return OS_ERR_NOT_IMPLEMENTED; } @@ -95,7 +95,7 @@ int32 OS_SocketShutdown_Impl(const OS_object_token_t *token, OS_SocketShutdownMo * See prototype for argument/return detail *-----------------------------------------------------------------*/ int32 OS_SocketAccept_Impl(const OS_object_token_t *sock_token, const OS_object_token_t *conn_token, - OS_SockAddr_t *Addr, int32 timeout) + OS_SockAddr_t *Addr, OS_time_t abs_timeout) { return OS_ERR_NOT_IMPLEMENTED; } @@ -106,7 +106,7 @@ int32 OS_SocketAccept_Impl(const OS_object_token_t *sock_token, const OS_object_ * See prototype for argument/return detail *-----------------------------------------------------------------*/ int32 OS_SocketRecvFrom_Impl(const OS_object_token_t *token, void *buffer, size_t buflen, OS_SockAddr_t *RemoteAddr, - int32 timeout) + OS_time_t abs_timeout) { return OS_ERR_NOT_IMPLEMENTED; } diff --git a/src/os/portable/os-impl-posix-io.c b/src/os/portable/os-impl-posix-io.c index 5d9dc3b1e..9a0da4d8b 100644 --- a/src/os/portable/os-impl-posix-io.c +++ b/src/os/portable/os-impl-posix-io.c @@ -162,7 +162,7 @@ int32 OS_GenericSeek_Impl(const OS_object_token_t *token, int32 offset, uint32 w * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_GenericRead_Impl(const OS_object_token_t *token, void *buffer, size_t nbytes, int32 timeout) +int32 OS_GenericRead_Impl(const OS_object_token_t *token, void *buffer, size_t nbytes, OS_time_t abs_timeout) { int32 return_code; ssize_t os_result; @@ -187,7 +187,7 @@ int32 OS_GenericRead_Impl(const OS_object_token_t *token, void *buffer, size_t n */ if (impl->selectable) { - return_code = OS_SelectSingle_Impl(token, &operation, timeout); + return_code = OS_SelectSingle_Impl(token, &operation, abs_timeout); } if (return_code == OS_SUCCESS && (operation & OS_STREAM_STATE_READABLE) != 0) @@ -215,7 +215,7 @@ int32 OS_GenericRead_Impl(const OS_object_token_t *token, void *buffer, size_t n * See prototype for argument/return detail * *-----------------------------------------------------------------*/ -int32 OS_GenericWrite_Impl(const OS_object_token_t *token, const void *buffer, size_t nbytes, int32 timeout) +int32 OS_GenericWrite_Impl(const OS_object_token_t *token, const void *buffer, size_t nbytes, OS_time_t abs_timeout) { int32 return_code; ssize_t os_result; @@ -240,7 +240,7 @@ int32 OS_GenericWrite_Impl(const OS_object_token_t *token, const void *buffer, s */ if (impl->selectable) { - return_code = OS_SelectSingle_Impl(token, &operation, timeout); + return_code = OS_SelectSingle_Impl(token, &operation, abs_timeout); } if (return_code == OS_SUCCESS && (operation & OS_STREAM_STATE_WRITABLE) != 0) diff --git a/src/os/shared/inc/os-shared-file.h b/src/os/shared/inc/os-shared-file.h index 8c21f3bb4..a96797a74 100644 --- a/src/os/shared/inc/os-shared-file.h +++ b/src/os/shared/inc/os-shared-file.h @@ -85,7 +85,7 @@ int32 OS_GenericSeek_Impl(const OS_object_token_t *token, int32 offset, uint32 w Returns: Number of bytes read (non-negative) on success, or relevant error code (negative) ------------------------------------------------------------------*/ -int32 OS_GenericRead_Impl(const OS_object_token_t *token, void *buffer, size_t nbytes, int32 timeout); +int32 OS_GenericRead_Impl(const OS_object_token_t *token, void *buffer, size_t nbytes, OS_time_t abs_timeout); /*---------------------------------------------------------------- @@ -94,7 +94,7 @@ int32 OS_GenericRead_Impl(const OS_object_token_t *token, void *buffer, size_t n Returns: Number of bytes written (non-negative) on success, or relevant error code (negative) ------------------------------------------------------------------*/ -int32 OS_GenericWrite_Impl(const OS_object_token_t *token, const void *buffer, size_t nbytes, int32 timeout); +int32 OS_GenericWrite_Impl(const OS_object_token_t *token, const void *buffer, size_t nbytes, OS_time_t abs_timeout); /*---------------------------------------------------------------- diff --git a/src/os/shared/inc/os-shared-select.h b/src/os/shared/inc/os-shared-select.h index a2123762e..6d610e9b1 100644 --- a/src/os/shared/inc/os-shared-select.h +++ b/src/os/shared/inc/os-shared-select.h @@ -26,6 +26,7 @@ #ifndef OS_SHARED_SELECT_H #define OS_SHARED_SELECT_H +#include "osapi-clock.h" #include "osapi-select.h" #include "os-shared-globaldefs.h" @@ -48,7 +49,7 @@ Returns: OS_SUCCESS on success, or relevant error code OS_ERR_OPERATION_NOT_SUPPORTED if the specified file handle does not support select ------------------------------------------------------------------*/ -int32 OS_SelectSingle_Impl(const OS_object_token_t *token, uint32 *SelectFlags, int32 msecs); +int32 OS_SelectSingle_Impl(const OS_object_token_t *token, uint32 *SelectFlags, OS_time_t abs_timeout); /*---------------------------------------------------------------- @@ -71,6 +72,6 @@ int32 OS_SelectSingle_Impl(const OS_object_token_t *token, uint32 *SelectFlags, Returns: OS_SUCCESS on success, or relevant error code OS_ERR_OPERATION_NOT_SUPPORTED if the specified file handle(s) do not support select ------------------------------------------------------------------*/ -int32 OS_SelectMultiple_Impl(OS_FdSet *ReadSet, OS_FdSet *WriteSet, int32 msecs); +int32 OS_SelectMultiple_Impl(OS_FdSet *ReadSet, OS_FdSet *WriteSet, OS_time_t abs_timeout); #endif /* OS_SHARED_SELECT_H */ diff --git a/src/os/shared/inc/os-shared-sockets.h b/src/os/shared/inc/os-shared-sockets.h index 547d011f6..c1989bd92 100644 --- a/src/os/shared/inc/os-shared-sockets.h +++ b/src/os/shared/inc/os-shared-sockets.h @@ -75,7 +75,7 @@ int32 OS_SocketListen_Impl(const OS_object_token_t *token); Returns: OS_SUCCESS on success, or relevant error code ------------------------------------------------------------------*/ int32 OS_SocketAccept_Impl(const OS_object_token_t *sock_token, const OS_object_token_t *conn_token, - OS_SockAddr_t *Addr, int32 timeout); + OS_SockAddr_t *Addr, OS_time_t abs_timeout); /*---------------------------------------------------------------- @@ -84,7 +84,7 @@ int32 OS_SocketAccept_Impl(const OS_object_token_t *sock_token, const OS_object_ Returns: OS_SUCCESS on success, or relevant error code ------------------------------------------------------------------*/ -int32 OS_SocketConnect_Impl(const OS_object_token_t *token, const OS_SockAddr_t *Addr, int32 timeout); +int32 OS_SocketConnect_Impl(const OS_object_token_t *token, const OS_SockAddr_t *Addr, OS_time_t abs_timeout); /*---------------------------------------------------------------- @@ -105,7 +105,7 @@ int32 OS_SocketShutdown_Impl(const OS_object_token_t *token, OS_SocketShutdownMo Returns: OS_SUCCESS on success, or relevant error code ------------------------------------------------------------------*/ int32 OS_SocketRecvFrom_Impl(const OS_object_token_t *token, void *buffer, size_t buflen, OS_SockAddr_t *RemoteAddr, - int32 timeout); + OS_time_t abs_timeout); /*---------------------------------------------------------------- diff --git a/src/os/shared/src/osapi-clock.c b/src/os/shared/src/osapi-clock.c index bd42eb0c7..2cd0b0448 100644 --- a/src/os/shared/src/osapi-clock.c +++ b/src/os/shared/src/osapi-clock.c @@ -65,3 +65,83 @@ int32 OS_SetLocalTime(const OS_time_t *time_struct) return OS_SetLocalTime_Impl(time_struct); } + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + * Helper function to convert a relative timeout to absolute time + * + *-----------------------------------------------------------------*/ +OS_time_t OS_TimeFromRelativeMilliseconds(int32 relative_msec) +{ + OS_time_t abs_time; + + if (relative_msec == OS_CHECK) + { + abs_time = OS_TIME_ZERO; + } + else if (relative_msec > 0) + { + OS_GetLocalTime_Impl(&abs_time); + abs_time = OS_TimeAdd(abs_time, OS_TimeFromTotalMilliseconds(relative_msec)); + } + else + { + abs_time = OS_TIME_MAX; + } + + return abs_time; +} + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + * Helper function to convert an absolute time to relative timeout + * + *-----------------------------------------------------------------*/ +int32 OS_TimeToRelativeMilliseconds(OS_time_t time) +{ + int64 relative_msec; + OS_time_t curr_time; + + /* + * This is an optimization that assumes all negative time values are + * in the past - no need to read the clock to figure that out. + * + * Also OS_TIME_MAX is equivalent to pend forever, and does not + * need to read the clock either. + */ + if (OS_TimeGetSign(time) <= 0 || OS_TimeEqual(time, OS_TIME_MAX)) + { + curr_time = time; + } + else + { + OS_GetLocalTime_Impl(&curr_time); + curr_time = OS_TimeSubtract(time, curr_time); + } + + if (OS_TimeGetSign(curr_time) <= 0) + { + /* map this to a polling op (OS_CHECK) */ + relative_msec = OS_CHECK; + } + else + { + /* note this result is 64 bits, as this can exceed int32 potentially */ + relative_msec = OS_TimeGetTotalMilliseconds(curr_time); + + /* Just in case: cap the value at INT32_MAX */ + if (relative_msec > INT32_MAX) + { + /* map this to an indefinite block (OS_PEND) */ + relative_msec = OS_PEND; + } + } + + return relative_msec; +} diff --git a/src/os/shared/src/osapi-file.c b/src/os/shared/src/osapi-file.c index da5eb7a05..3d72e1324 100644 --- a/src/os/shared/src/osapi-file.c +++ b/src/os/shared/src/osapi-file.c @@ -182,7 +182,7 @@ int32 OS_close(osal_id_t filedes) * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_TimedRead(osal_id_t filedes, void *buffer, size_t nbytes, int32 timeout) +int32 OS_TimedReadAbs(osal_id_t filedes, void *buffer, size_t nbytes, OS_time_t abstime) { OS_object_token_t token; int32 return_code; @@ -194,7 +194,7 @@ int32 OS_TimedRead(osal_id_t filedes, void *buffer, size_t nbytes, int32 timeout return_code = OS_ObjectIdGetById(OS_LOCK_MODE_REFCOUNT, LOCAL_OBJID_TYPE, filedes, &token); if (return_code == OS_SUCCESS) { - return_code = OS_GenericRead_Impl(&token, buffer, nbytes, timeout); + return_code = OS_GenericRead_Impl(&token, buffer, nbytes, abstime); OS_ObjectIdRelease(&token); } @@ -208,7 +208,18 @@ int32 OS_TimedRead(osal_id_t filedes, void *buffer, size_t nbytes, int32 timeout * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_TimedWrite(osal_id_t filedes, const void *buffer, size_t nbytes, int32 timeout) +int32 OS_TimedRead(osal_id_t filedes, void *buffer, size_t nbytes, int32 timeout) +{ + return OS_TimedReadAbs(filedes, buffer, nbytes, OS_TimeFromRelativeMilliseconds(timeout)); +} + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_TimedWriteAbs(osal_id_t filedes, const void *buffer, size_t nbytes, OS_time_t abstime) { OS_object_token_t token; int32 return_code; @@ -220,13 +231,24 @@ int32 OS_TimedWrite(osal_id_t filedes, const void *buffer, size_t nbytes, int32 return_code = OS_ObjectIdGetById(OS_LOCK_MODE_REFCOUNT, LOCAL_OBJID_TYPE, filedes, &token); if (return_code == OS_SUCCESS) { - return_code = OS_GenericWrite_Impl(&token, buffer, nbytes, timeout); + return_code = OS_GenericWrite_Impl(&token, buffer, nbytes, abstime); OS_ObjectIdRelease(&token); } return return_code; } +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_TimedWrite(osal_id_t filedes, const void *buffer, size_t nbytes, int32 timeout) +{ + return OS_TimedWriteAbs(filedes, buffer, nbytes, OS_TimeFromRelativeMilliseconds(timeout)); +} + /*---------------------------------------------------------------- * * Purpose: Implemented per public OSAL API diff --git a/src/os/shared/src/osapi-select.c b/src/os/shared/src/osapi-select.c index 21778cfb1..b1ea036a3 100644 --- a/src/os/shared/src/osapi-select.c +++ b/src/os/shared/src/osapi-select.c @@ -54,7 +54,7 @@ * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_SelectSingle(osal_id_t objid, uint32 *StateFlags, int32 msecs) +int32 OS_SelectSingleAbs(osal_id_t objid, uint32 *StateFlags, OS_time_t abs_timeout) { int32 return_code; OS_object_token_t token; @@ -65,7 +65,7 @@ int32 OS_SelectSingle(osal_id_t objid, uint32 *StateFlags, int32 msecs) return_code = OS_ObjectIdGetById(OS_LOCK_MODE_REFCOUNT, OS_OBJECT_TYPE_OS_STREAM, objid, &token); if (return_code == OS_SUCCESS) { - return_code = OS_SelectSingle_Impl(&token, StateFlags, msecs); + return_code = OS_SelectSingle_Impl(&token, StateFlags, abs_timeout); OS_ObjectIdRelease(&token); } @@ -79,7 +79,18 @@ int32 OS_SelectSingle(osal_id_t objid, uint32 *StateFlags, int32 msecs) * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_SelectMultiple(OS_FdSet *ReadSet, OS_FdSet *WriteSet, int32 msecs) +int32 OS_SelectSingle(osal_id_t objid, uint32 *StateFlags, int32 msecs) +{ + return OS_SelectSingleAbs(objid, StateFlags, OS_TimeFromRelativeMilliseconds(msecs)); +} + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_SelectMultipleAbs(OS_FdSet *ReadSet, OS_FdSet *WriteSet, OS_time_t abs_timeout) { int32 return_code; @@ -94,11 +105,22 @@ int32 OS_SelectMultiple(OS_FdSet *ReadSet, OS_FdSet *WriteSet, int32 msecs) * That means a file/socket can be closed while actively inside a * OS_SelectMultiple() call in another thread. */ - return_code = OS_SelectMultiple_Impl(ReadSet, WriteSet, msecs); + return_code = OS_SelectMultiple_Impl(ReadSet, WriteSet, abs_timeout); return return_code; } +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_SelectMultiple(OS_FdSet *ReadSet, OS_FdSet *WriteSet, int32 msecs) +{ + return OS_SelectMultipleAbs(ReadSet, WriteSet, OS_TimeFromRelativeMilliseconds(msecs)); +} + /*---------------------------------------------------------------- * * Purpose: Implemented per public OSAL API diff --git a/src/os/shared/src/osapi-sockets.c b/src/os/shared/src/osapi-sockets.c index 6e47ffe1d..e980de6b9 100644 --- a/src/os/shared/src/osapi-sockets.c +++ b/src/os/shared/src/osapi-sockets.c @@ -281,7 +281,7 @@ int32 OS_SocketBindAddress(osal_id_t sock_id, const OS_SockAddr_t *Addr) * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_SocketAccept(osal_id_t sock_id, osal_id_t *connsock_id, OS_SockAddr_t *Addr, int32 timeout) +int32 OS_SocketAcceptAbs(osal_id_t sock_id, osal_id_t *connsock_id, OS_SockAddr_t *Addr, OS_time_t abs_timeout) { OS_common_record_t * sock_record; OS_common_record_t * conn_record; @@ -342,7 +342,7 @@ int32 OS_SocketAccept(osal_id_t sock_id, osal_id_t *connsock_id, OS_SockAddr_t * OS_SocketAddrInit_Impl(Addr, sock->socket_domain); - return_code = OS_SocketAccept_Impl(&sock_token, &conn_token, Addr, timeout); + return_code = OS_SocketAccept_Impl(&sock_token, &conn_token, Addr, abs_timeout); if (return_code == OS_SUCCESS) { @@ -368,7 +368,18 @@ int32 OS_SocketAccept(osal_id_t sock_id, osal_id_t *connsock_id, OS_SockAddr_t * * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_SocketConnect(osal_id_t sock_id, const OS_SockAddr_t *Addr, int32 Timeout) +int32 OS_SocketAccept(osal_id_t sock_id, osal_id_t *connsock_id, OS_SockAddr_t *Addr, int32 timeout) +{ + return OS_SocketAcceptAbs(sock_id, connsock_id, Addr, OS_TimeFromRelativeMilliseconds(timeout)); +} + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_SocketConnectAbs(osal_id_t sock_id, const OS_SockAddr_t *Addr, OS_time_t abs_timeout) { OS_stream_internal_record_t *stream; OS_object_token_t token; @@ -393,7 +404,7 @@ int32 OS_SocketConnect(osal_id_t sock_id, const OS_SockAddr_t *Addr, int32 Timeo } else { - return_code = OS_SocketConnect_Impl(&token, Addr, Timeout); + return_code = OS_SocketConnect_Impl(&token, Addr, abs_timeout); if (return_code == OS_SUCCESS) { @@ -467,7 +478,19 @@ int32 OS_SocketShutdown(osal_id_t sock_id, OS_SocketShutdownMode_t Mode) * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_SocketRecvFrom(osal_id_t sock_id, void *buffer, size_t buflen, OS_SockAddr_t *RemoteAddr, int32 timeout) +int32 OS_SocketConnect(osal_id_t sock_id, const OS_SockAddr_t *Addr, int32 timeout) +{ + return OS_SocketConnectAbs(sock_id, Addr, OS_TimeFromRelativeMilliseconds(timeout)); +} + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_SocketRecvFromAbs(osal_id_t sock_id, void *buffer, size_t buflen, OS_SockAddr_t *RemoteAddr, + OS_time_t abs_timeout) { OS_stream_internal_record_t *stream; OS_object_token_t token; @@ -497,7 +520,7 @@ int32 OS_SocketRecvFrom(osal_id_t sock_id, void *buffer, size_t buflen, OS_SockA } else { - return_code = OS_SocketRecvFrom_Impl(&token, buffer, buflen, RemoteAddr, timeout); + return_code = OS_SocketRecvFrom_Impl(&token, buffer, buflen, RemoteAddr, abs_timeout); } OS_ObjectIdRelease(&token); @@ -506,6 +529,17 @@ int32 OS_SocketRecvFrom(osal_id_t sock_id, void *buffer, size_t buflen, OS_SockA return return_code; } +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_SocketRecvFrom(osal_id_t sock_id, void *buffer, size_t buflen, OS_SockAddr_t *RemoteAddr, int32 timeout) +{ + return OS_SocketRecvFromAbs(sock_id, buffer, buflen, RemoteAddr, OS_TimeFromRelativeMilliseconds(timeout)); +} + /*---------------------------------------------------------------- * * Purpose: Implemented per public OSAL API diff --git a/src/tests/network-api-test/network-api-test.c b/src/tests/network-api-test/network-api-test.c index f2426c3e2..e206feb2d 100644 --- a/src/tests/network-api-test/network-api-test.c +++ b/src/tests/network-api-test/network-api-test.c @@ -378,6 +378,8 @@ void Server_Fn(void) ServerFn_AcceptStatus = OS_SocketAccept(s_socket_id, &connsock_id, &addr, OS_PEND); if (ServerFn_AcceptStatus != OS_SUCCESS) { + snprintf(ServerFn_ErrorString, sizeof(ServerFn_ErrorString), "OS_SocketAccept() iter=%u, return code=%d", + (unsigned int)iter, (int)Status); break; } diff --git a/src/unit-test-coverage/portable/src/coveragetest-bsd-select.c b/src/unit-test-coverage/portable/src/coveragetest-bsd-select.c index 8a6fcb24e..06579d772 100644 --- a/src/unit-test-coverage/portable/src/coveragetest-bsd-select.c +++ b/src/unit-test-coverage/portable/src/coveragetest-bsd-select.c @@ -23,6 +23,7 @@ */ #include "os-portable-coveragetest.h" #include "ut-adaptor-portable-posix-io.h" +#include "os-shared-clock.h" #include "os-shared-select.h" #include "os-shared-idmap.h" @@ -34,89 +35,81 @@ void Test_OS_SelectSingle_Impl(void) /* Test Case For: * int32 OS_SelectSingle_Impl(uint32 stream_id, uint32 *SelectFlags, int32 msecs) */ - uint32 SelectFlags; - OS_object_token_t token; - struct OCS_timespec nowtime; - struct OCS_timespec latertime; - struct OCS_timespec latertime2; + uint32 SelectFlags; + OS_object_token_t token; + OS_time_t nowtime; + OS_time_t latertime; + OS_time_t timeout; memset(&token, 0, sizeof(token)); UT_PortablePosixIOTest_Set_Selectable(UT_INDEX_0, false); SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, 0), OS_ERR_OPERATION_NOT_SUPPORTED); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, OS_TIME_MIN), OS_ERR_OPERATION_NOT_SUPPORTED); UT_PortablePosixIOTest_Set_Selectable(UT_INDEX_0, true); - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, OS_TIME_MIN), OS_SUCCESS); /* Cover FD_ISSET true branches and pend */ UT_SetDeferredRetcode(UT_KEY(OCS_FD_ISSET), 1, true); UT_SetDeferredRetcode(UT_KEY(OCS_FD_ISSET), 1, true); SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, -1), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, OS_TIME_MAX), OS_SUCCESS); /* No flags and non-read/write flag branches */ SelectFlags = 0; - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, OS_TIME_MIN), OS_SUCCESS); SelectFlags = OS_STREAM_STATE_BOUND; - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, OS_TIME_MIN), OS_SUCCESS); /* try a case where select() needs to be repeated to achieve the desired wait time */ - UT_ResetState(UT_KEY(OCS_clock_gettime)); UT_ResetState(UT_KEY(OCS_select)); UT_SetDefaultReturnValue(UT_KEY(OCS_select), -1); OCS_errno = OCS_EINTR; UT_SetDeferredRetcode(UT_KEY(OCS_select), 2, 0); - SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; - nowtime.tv_sec = 1; - nowtime.tv_nsec = 0; - latertime.tv_sec = 1; - latertime.tv_nsec = 800000000; - latertime2.tv_sec = 2; - latertime2.tv_nsec = 200000000; - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &nowtime, sizeof(nowtime), false); - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &latertime, sizeof(latertime), false); - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &latertime2, sizeof(latertime2), false); - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, 1200), OS_ERROR_TIMEOUT); - UtAssert_STUB_COUNT(OCS_clock_gettime, 3); + SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; + nowtime = OS_TimeFromTotalMilliseconds(1000); + latertime = OS_TimeFromTotalMilliseconds(1800); + timeout = OS_TimeFromTotalMilliseconds(1200); + UT_SetDataBuffer(UT_KEY(OS_GetLocalTime_Impl), &nowtime, sizeof(nowtime), false); + UT_SetDataBuffer(UT_KEY(OS_GetLocalTime_Impl), &latertime, sizeof(latertime), false); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, timeout), OS_ERROR_TIMEOUT); + UtAssert_STUB_COUNT(OS_GetLocalTime_Impl, 2); UtAssert_STUB_COUNT(OCS_select, 2); /* Repeated select with alternate branches */ - OCS_errno = OCS_EAGAIN; - SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; - latertime2.tv_nsec = 300000000; - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &nowtime, sizeof(nowtime), false); - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &latertime, sizeof(latertime), false); - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &latertime2, sizeof(latertime2), false); - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, 1200), OS_ERROR_TIMEOUT); - UtAssert_STUB_COUNT(OCS_clock_gettime, 6); - UtAssert_STUB_COUNT(OCS_select, 3); + OCS_errno = OCS_EAGAIN; + SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; + UT_SetDeferredRetcode(UT_KEY(OCS_select), 2, 0); + UT_SetDataBuffer(UT_KEY(OS_GetLocalTime_Impl), &nowtime, sizeof(nowtime), false); + UT_SetDataBuffer(UT_KEY(OS_GetLocalTime_Impl), &latertime, sizeof(latertime), false); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, timeout), OS_ERROR_TIMEOUT); + UtAssert_STUB_COUNT(OS_GetLocalTime_Impl, 4); + UtAssert_STUB_COUNT(OCS_select, 4); UT_SetDefaultReturnValue(UT_KEY(OCS_select), 0); - SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; - nowtime.tv_sec = 1; - nowtime.tv_nsec = 500000000; - latertime.tv_sec = 10; - latertime.tv_nsec = 0; - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &nowtime, sizeof(nowtime), false); - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &latertime, sizeof(latertime), false); - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, 999), OS_ERROR_TIMEOUT); + SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; + nowtime = OS_TimeFromTotalMilliseconds(1500); + latertime = OS_TimeFromTotalMilliseconds(10000); + timeout = OS_TimeFromTotalMilliseconds(999); + UT_SetDataBuffer(UT_KEY(OS_GetLocalTime_Impl), &nowtime, sizeof(nowtime), false); + UT_SetDataBuffer(UT_KEY(OS_GetLocalTime_Impl), &latertime, sizeof(latertime), false); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, timeout), OS_ERROR_TIMEOUT); UT_SetDefaultReturnValue(UT_KEY(OCS_select), -1); - OCS_errno = OCS_ETIMEDOUT; - SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; - nowtime.tv_sec = 1; - nowtime.tv_nsec = 0; - latertime.tv_sec = 2; - latertime.tv_nsec = 600000000; - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &nowtime, sizeof(nowtime), false); - UT_SetDataBuffer(UT_KEY(OCS_clock_gettime), &latertime, sizeof(latertime), false); - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, 2100), OS_ERROR); + OCS_errno = OCS_ETIMEDOUT; + SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; + nowtime = OS_TimeFromTotalMilliseconds(1000); + latertime = OS_TimeFromTotalMilliseconds(2600); + timeout = OS_TimeFromTotalMilliseconds(2100); + UT_SetDataBuffer(UT_KEY(OS_GetLocalTime_Impl), &nowtime, sizeof(nowtime), false); + UT_SetDataBuffer(UT_KEY(OS_GetLocalTime_Impl), &latertime, sizeof(latertime), false); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, timeout), OS_ERROR); /* Test cases where the FD exceeds FD_SETSIZE */ SelectFlags = OS_STREAM_STATE_READABLE | OS_STREAM_STATE_WRITABLE; UT_PortablePosixIOTest_Set_FD(UT_INDEX_0, OCS_FD_SETSIZE); UT_PortablePosixIOTest_Set_Selectable(UT_INDEX_0, true); - OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, 0), OS_ERR_OPERATION_NOT_SUPPORTED); + OSAPI_TEST_FUNCTION_RC(OS_SelectSingle_Impl, (&token, &SelectFlags, OS_TIME_MIN), OS_ERR_OPERATION_NOT_SUPPORTED); } void Test_OS_SelectMultiple_Impl(void) @@ -134,9 +127,9 @@ void Test_OS_SelectMultiple_Impl(void) memset(&ReadSet, 0, sizeof(ReadSet)); memset(&WriteSet, 0, sizeof(WriteSet)); WriteSet.object_ids[0] = 1; - OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (NULL, &WriteSet, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (NULL, &WriteSet, OS_TIME_MIN), OS_SUCCESS); ReadSet.object_ids[0] = 1; - OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, NULL, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, NULL, OS_TIME_MIN), OS_SUCCESS); /* Branches for processing the set */ UT_SetDeferredRetcode(UT_KEY(OCS_FD_ISSET), 1, true); @@ -144,37 +137,37 @@ void Test_OS_SelectMultiple_Impl(void) UT_PortablePosixIOTest_Set_FD(OSAL_INDEX_C(2), -1); UT_PortablePosixIOTest_Set_FD(OSAL_INDEX_C(3), 0); UT_PortablePosixIOTest_Set_Selectable(OSAL_INDEX_C(3), true); - OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, OS_TIME_MIN), OS_SUCCESS); memset(&ReadSet, 0, sizeof(ReadSet)); memset(&WriteSet, 0, sizeof(WriteSet)); ReadSet.object_ids[0] = 1; UT_SetDeferredRetcode(UT_KEY(OCS_select), 1, 0); - OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, 1), OS_ERROR_TIMEOUT); + OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, OS_TIME_MAX), OS_ERROR_TIMEOUT); /* Test where the FD set is empty */ memset(&ReadSet, 0, sizeof(ReadSet)); memset(&WriteSet, 0, sizeof(WriteSet)); - OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (NULL, NULL, 0), OS_ERR_INVALID_ID); + OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (NULL, NULL, OS_TIME_MIN), OS_ERR_INVALID_ID); /* Test cases where the FD exceeds FD_SETSIZE in the read set */ UT_PortablePosixIOTest_Set_FD(UT_INDEX_0, OCS_FD_SETSIZE); UT_PortablePosixIOTest_Set_Selectable(UT_INDEX_0, true); memset(&ReadSet, 0xff, sizeof(ReadSet)); memset(&WriteSet, 0, sizeof(WriteSet)); - OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, 0), OS_ERR_OPERATION_NOT_SUPPORTED); + OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, OS_TIME_MIN), OS_ERR_OPERATION_NOT_SUPPORTED); /* Test cases where the FD exceeds FD_SETSIZE in the write set */ memset(&ReadSet, 0, sizeof(ReadSet)); memset(&WriteSet, 0xff, sizeof(WriteSet)); - OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, 0), OS_ERR_OPERATION_NOT_SUPPORTED); + OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, OS_TIME_MIN), OS_ERR_OPERATION_NOT_SUPPORTED); /* Test cases where additional bits are set in the OS_FdSet */ UT_PortablePosixIOTest_Set_FD(UT_INDEX_0, 0); UT_PortablePosixIOTest_Set_Selectable(UT_INDEX_0, true); memset(&ReadSet, 0xff, sizeof(ReadSet)); memset(&WriteSet, 0xff, sizeof(WriteSet)); - OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, 0), OS_ERR_OPERATION_NOT_SUPPORTED); + OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, OS_TIME_MIN), OS_ERR_OPERATION_NOT_SUPPORTED); /* * Cover OS_FdSet_ConvertOut_Impl for id < OS_MAX_NUM_OPEN_FILES, requires no errors from in conversion @@ -184,7 +177,7 @@ void Test_OS_SelectMultiple_Impl(void) { UT_PortablePosixIOTest_Set_FD(OSAL_INDEX_C(i), -1); } - OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SelectMultiple_Impl, (&ReadSet, &WriteSet, OS_TIME_MIN), OS_SUCCESS); } /* ------------------- End of test cases --------------------------------------*/ diff --git a/src/unit-test-coverage/portable/src/coveragetest-bsd-sockets.c b/src/unit-test-coverage/portable/src/coveragetest-bsd-sockets.c index 90c8459bd..bfa41d1c8 100644 --- a/src/unit-test-coverage/portable/src/coveragetest-bsd-sockets.c +++ b/src/unit-test-coverage/portable/src/coveragetest-bsd-sockets.c @@ -188,16 +188,16 @@ void Test_OS_SocketConnect_Impl(void) /* Default family case */ sa->sa_family = -1; addr.ActualLength = sizeof(struct OCS_sockaddr_in); - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, 0), OS_ERR_BAD_ADDRESS); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, OS_TIME_MIN), OS_ERR_BAD_ADDRESS); /* Successful connect */ sa->sa_family = OCS_AF_INET; - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, OS_TIME_MIN), OS_SUCCESS); /* Fail connect, errno ! EINPROGRESS */ OCS_errno = ~OCS_EINPROGRESS; UT_SetDefaultReturnValue(UT_KEY(OCS_connect), -1); - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, 0), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, OS_TIME_MIN), OS_ERROR); /* Fail OS_SelectSingle_Impl, errno == EINPROGRESS */ OCS_errno = OCS_EINPROGRESS; @@ -205,30 +205,30 @@ void Test_OS_SocketConnect_Impl(void) addr.ActualLength = sizeof(struct OCS_sockaddr_in6); OS_impl_filehandle_table[0].selectable = true; UT_SetDeferredRetcode(UT_KEY(OS_SelectSingle_Impl), 1, UT_ERR_UNIQUE); - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, 0), UT_ERR_UNIQUE); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, OS_TIME_MIN), UT_ERR_UNIQUE); /* Timeout error by clearing select flags with hook */ selectflags = 0; UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), UT_Hook_OS_SelectSingle_Impl, &selectflags); - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, 0), OS_ERROR_TIMEOUT); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, OS_TIME_MIN), OS_ERROR_TIMEOUT); UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), NULL, NULL); /* Fail getsockopt status */ UT_SetDeferredRetcode(UT_KEY(OCS_getsockopt), 1, -1); - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, 0), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, OS_TIME_MIN), OS_ERROR); /* Nonzero getsockopt sockopt */ sockopt = 1; UT_SetHookFunction(UT_KEY(OCS_getsockopt), UT_Hook_OCS_getsockopt, &sockopt); - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, 0), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, OS_TIME_MIN), OS_ERROR); UT_SetHookFunction(UT_KEY(OCS_getsockopt), NULL, NULL); /* Success case with selectable */ - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, OS_TIME_MIN), OS_SUCCESS); /* Success case with not selectable */ OS_impl_filehandle_table[0].selectable = false; - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (&token, &addr, OS_TIME_MIN), OS_SUCCESS); } void Test_OS_SocketShutdown_Impl(void) @@ -262,21 +262,21 @@ void Test_OS_SocketAccept_Impl(void) /* Fail OS_SelectSingle_Impl with sock_token selectable */ OS_impl_filehandle_table[0].selectable = true; UT_SetDeferredRetcode(UT_KEY(OS_SelectSingle_Impl), 1, UT_ERR_UNIQUE); - OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (&sock_token, &conn_token, &addr, 0), UT_ERR_UNIQUE); + OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (&sock_token, &conn_token, &addr, OS_TIME_MIN), UT_ERR_UNIQUE); /* Timeout by clearing select flags with hook */ selectflags = 0; UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), UT_Hook_OS_SelectSingle_Impl, &selectflags); - OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (&sock_token, &conn_token, &addr, 0), OS_ERROR_TIMEOUT); + OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (&sock_token, &conn_token, &addr, OS_TIME_MIN), OS_ERROR_TIMEOUT); UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), NULL, NULL); /* Clear selectable and fail accept */ OS_impl_filehandle_table[0].selectable = false; UT_SetDeferredRetcode(UT_KEY(OCS_accept), 1, -1); - OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (&sock_token, &conn_token, &addr, 0), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (&sock_token, &conn_token, &addr, OS_TIME_MIN), OS_ERROR); /* Success case */ - OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (&sock_token, &conn_token, &addr, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (&sock_token, &conn_token, &addr, OS_TIME_MIN), OS_SUCCESS); } void Test_OS_SocketRecvFrom_Impl(void) @@ -292,35 +292,39 @@ void Test_OS_SocketRecvFrom_Impl(void) /* NULL RemoteAddr, selectable, fail OS_SelectSingle_Impl */ OS_impl_filehandle_table[0].selectable = true; UT_SetDeferredRetcode(UT_KEY(OS_SelectSingle_Impl), 1, UT_ERR_UNIQUE); - OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), NULL, 0), UT_ERR_UNIQUE); + OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), NULL, OS_TIME_MIN), UT_ERR_UNIQUE); /* Timeout by clearing select flags with hook */ selectflags = 0; UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), UT_Hook_OS_SelectSingle_Impl, &selectflags); - OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, 0), OS_ERROR_TIMEOUT); + OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, OS_TIME_MIN), + OS_ERROR_TIMEOUT); UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), NULL, NULL); /* Not selectable, 0 timeout, EAGAIN error from recvfrom error */ OS_impl_filehandle_table[0].selectable = false; OCS_errno = OCS_EAGAIN; UT_SetDeferredRetcode(UT_KEY(OCS_recvfrom), 1, -1); - OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, 0), OS_QUEUE_EMPTY); + OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, OS_TIME_MIN), + OS_QUEUE_EMPTY); /* With timeout, other error from recvfrom error */ OCS_errno = 0; UT_SetDeferredRetcode(UT_KEY(OCS_recvfrom), 1, -1); - OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, 1), OS_ERROR); + UT_SetDeferredRetcode(UT_KEY(OS_TimeToRelativeMilliseconds), 1, OS_PEND); + OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, OS_TIME_MAX), OS_ERROR); /* With timeout, EWOULDBLOCK error from recvfrom error */ OCS_errno = OCS_EWOULDBLOCK; UT_SetDeferredRetcode(UT_KEY(OCS_recvfrom), 1, -1); - OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, 1), OS_QUEUE_EMPTY); + OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, OS_TIME_MAX), + OS_QUEUE_EMPTY); /* Success with NULL RemoteAddr */ - OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), NULL, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), NULL, OS_TIME_MIN), OS_SUCCESS); /* Success with non-NULL RemoteAddr */ - OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (&token, buffer, sizeof(buffer), &addr, OS_TIME_MIN), OS_SUCCESS); } void Test_OS_SocketSendTo_Impl(void) diff --git a/src/unit-test-coverage/portable/src/coveragetest-no-sockets.c b/src/unit-test-coverage/portable/src/coveragetest-no-sockets.c index 71a274180..6013b9637 100644 --- a/src/unit-test-coverage/portable/src/coveragetest-no-sockets.c +++ b/src/unit-test-coverage/portable/src/coveragetest-no-sockets.c @@ -29,10 +29,10 @@ void Test_No_Sockets(void) OSAPI_TEST_FUNCTION_RC(OS_SocketOpen_Impl, (NULL), OS_ERR_NOT_IMPLEMENTED); OSAPI_TEST_FUNCTION_RC(OS_SocketBindAddress_Impl, (NULL, NULL), OS_ERR_NOT_IMPLEMENTED); OSAPI_TEST_FUNCTION_RC(OS_SocketListen_Impl, (NULL), OS_ERR_NOT_IMPLEMENTED); - OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (NULL, NULL, 0), OS_ERR_NOT_IMPLEMENTED); - OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (NULL, NULL, NULL, 0), OS_ERR_NOT_IMPLEMENTED); + OSAPI_TEST_FUNCTION_RC(OS_SocketConnect_Impl, (NULL, NULL, OS_TIME_MIN), OS_ERR_NOT_IMPLEMENTED); + OSAPI_TEST_FUNCTION_RC(OS_SocketAccept_Impl, (NULL, NULL, NULL, OS_TIME_MIN), OS_ERR_NOT_IMPLEMENTED); OSAPI_TEST_FUNCTION_RC(OS_SocketShutdown_Impl, (NULL, 0), OS_ERR_NOT_IMPLEMENTED); - OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (NULL, NULL, 0, NULL, 0), OS_ERR_NOT_IMPLEMENTED); + OSAPI_TEST_FUNCTION_RC(OS_SocketRecvFrom_Impl, (NULL, NULL, 0, NULL, OS_TIME_MIN), OS_ERR_NOT_IMPLEMENTED); OSAPI_TEST_FUNCTION_RC(OS_SocketSendTo_Impl, (NULL, NULL, 0, NULL), OS_ERR_NOT_IMPLEMENTED); OSAPI_TEST_FUNCTION_RC(OS_SocketGetInfo_Impl, (NULL, NULL), OS_SUCCESS); OSAPI_TEST_FUNCTION_RC(OS_SocketAddrInit_Impl, (NULL, 0), OS_ERR_NOT_IMPLEMENTED); diff --git a/src/unit-test-coverage/portable/src/coveragetest-posix-io.c b/src/unit-test-coverage/portable/src/coveragetest-posix-io.c index e6a5a7708..737689978 100644 --- a/src/unit-test-coverage/portable/src/coveragetest-posix-io.c +++ b/src/unit-test-coverage/portable/src/coveragetest-posix-io.c @@ -115,30 +115,30 @@ void Test_OS_GenericRead_Impl(void) UT_SetDataBuffer(UT_KEY(OCS_read), SrcData, sizeof(SrcData), false); UT_PortablePosixIOTest_Set_Selectable(UT_INDEX_0, false); - OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), 0), sizeof(DestData)); + OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), OS_TIME_MIN), sizeof(DestData)); UtAssert_MemCmp(SrcData, DestData, sizeof(SrcData), "read() data Valid"); /* test invocation of select() in nonblocking mode */ UT_ResetState(UT_KEY(OCS_read)); UT_SetDataBuffer(UT_KEY(OCS_read), SrcData, sizeof(SrcData), false); UT_PortablePosixIOTest_Set_Selectable(UT_INDEX_0, true); - OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), 0), sizeof(DestData)); + OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), OS_TIME_MIN), sizeof(DestData)); UtAssert_True(UT_GetStubCount(UT_KEY(OS_SelectSingle_Impl)) == 1, "OS_SelectSingle() called"); /* Read 0 bytes */ - OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, 0, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, 0, OS_TIME_MIN), OS_SUCCESS); /* read() failure */ UT_SetDefaultReturnValue(UT_KEY(OCS_read), -1); - OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), 0), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), OS_TIME_MIN), OS_ERROR); /* Fail select */ UT_SetDeferredRetcode(UT_KEY(OS_SelectSingle_Impl), 1, OS_ERROR_TIMEOUT); - OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), 0), OS_ERROR_TIMEOUT); + OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), OS_TIME_MIN), OS_ERROR_TIMEOUT); /* Not readable */ UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), UT_Hook_OS_SelectSingle_Impl, NULL); - OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_GenericRead_Impl, (&token, DestData, sizeof(DestData), OS_TIME_MIN), OS_SUCCESS); UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), NULL, NULL); } @@ -156,30 +156,30 @@ void Test_OS_GenericWrite_Impl(void) UT_SetDataBuffer(UT_KEY(OCS_write), DestData, sizeof(DestData), false); UT_PortablePosixIOTest_Set_Selectable(UT_INDEX_0, false); - OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, sizeof(SrcData), 0), sizeof(SrcData)); + OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, sizeof(SrcData), OS_TIME_MIN), sizeof(SrcData)); UtAssert_MemCmp(SrcData, DestData, sizeof(SrcData), "write() data valid"); /* test invocation of select() in nonblocking mode */ UT_ResetState(UT_KEY(OCS_write)); UT_SetDataBuffer(UT_KEY(OCS_write), DestData, sizeof(DestData), false); UT_PortablePosixIOTest_Set_Selectable(UT_INDEX_0, true); - OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, sizeof(SrcData), 0), sizeof(SrcData)); + OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, sizeof(SrcData), OS_TIME_MIN), sizeof(SrcData)); UtAssert_True(UT_GetStubCount(UT_KEY(OS_SelectSingle_Impl)) == 1, "OS_SelectSingle() called"); /* Fail select */ UT_SetDeferredRetcode(UT_KEY(OS_SelectSingle_Impl), 1, OS_ERROR_TIMEOUT); - OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, sizeof(SrcData), 0), OS_ERROR_TIMEOUT); + OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, sizeof(SrcData), OS_TIME_MIN), OS_ERROR_TIMEOUT); /* Write 0 bytes */ - OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, 0, 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, 0, OS_TIME_MIN), OS_SUCCESS); /* write() failure */ UT_SetDefaultReturnValue(UT_KEY(OCS_write), -1); - OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, DestData, sizeof(DestData), 0), OS_ERROR); + OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, DestData, sizeof(DestData), OS_TIME_MIN), OS_ERROR); /* Not writeable */ UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), UT_Hook_OS_SelectSingle_Impl, NULL); - OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, sizeof(SrcData), 0), OS_SUCCESS); + OSAPI_TEST_FUNCTION_RC(OS_GenericWrite_Impl, (&token, SrcData, sizeof(SrcData), OS_TIME_MIN), OS_SUCCESS); UT_SetHookFunction(UT_KEY(OS_SelectSingle_Impl), NULL, NULL); } diff --git a/src/unit-test-coverage/shared/src/coveragetest-clock.c b/src/unit-test-coverage/shared/src/coveragetest-clock.c index 8590a0547..dae84ee71 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-clock.c +++ b/src/unit-test-coverage/shared/src/coveragetest-clock.c @@ -171,6 +171,31 @@ void Test_OS_TimeAccessConversions(void) UtAssert_UINT32_EQ(OS_TimeGetTotalNanoseconds(OS_TimeFromTotalNanoseconds(347230000)), 347230000); } +void Test_OS_TimeFromRelativeMilliseconds(void) +{ + /* + * Test Case For: + * OS_time_t OS_TimeFromRelativeMilliseconds(int32 relative_msec) + */ + + UtAssert_BOOL_TRUE(OS_TimeEqual(OS_TimeFromRelativeMilliseconds(1000), OS_TimeFromTotalSeconds(1))); + UtAssert_BOOL_TRUE(OS_TimeEqual(OS_TimeFromRelativeMilliseconds(OS_CHECK), OS_TIME_ZERO)); + UtAssert_BOOL_TRUE(OS_TimeEqual(OS_TimeFromRelativeMilliseconds(OS_PEND), OS_TIME_MAX)); +} + +void Test_OS_TimeToRelativeMilliseconds(void) +{ + /* + * Test Case For: + * int32 OS_TimeToRelativeMilliseconds(OS_time_t time) + */ + + UtAssert_INT32_EQ(OS_TimeToRelativeMilliseconds(OS_TIME_MAX), OS_PEND); + UtAssert_INT32_EQ(OS_TimeToRelativeMilliseconds(OS_TIME_ZERO), OS_CHECK); + UtAssert_INT32_EQ(OS_TimeToRelativeMilliseconds(OS_TIME_MIN), OS_CHECK); + UtAssert_INT32_EQ(OS_TimeToRelativeMilliseconds(OS_TimeFromTotalSeconds(1)), 1000); +} + /* Osapi_Test_Setup * * Purpose: @@ -197,4 +222,6 @@ void UtTest_Setup(void) ADD_TEST(OS_GetLocalTime); ADD_TEST(OS_SetLocalTime); ADD_TEST(OS_TimeAccessConversions); + ADD_TEST(OS_TimeFromRelativeMilliseconds); + ADD_TEST(OS_TimeToRelativeMilliseconds); } diff --git a/src/unit-test-coverage/ut-stubs/CMakeLists.txt b/src/unit-test-coverage/ut-stubs/CMakeLists.txt index b970cf8a2..d96eef819 100644 --- a/src/unit-test-coverage/ut-stubs/CMakeLists.txt +++ b/src/unit-test-coverage/ut-stubs/CMakeLists.txt @@ -21,7 +21,7 @@ add_library(ut_osapi_stub_headers INTERFACE) target_include_directories(ut_osapi_stub_headers INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/inc ) -target_link_libraries(ut_osapi_stub_headers INTERFACE +target_link_libraries(ut_osapi_stub_headers INTERFACE ut_assert ) @@ -163,6 +163,7 @@ add_custom_target(generate_osal_coverage_stubs # and are not public API calls. This is only compiled if used. add_library(ut_osapi_impl_stubs STATIC EXCLUDE_FROM_ALL src/os-shared-binsem-impl-stubs.c + src/os-shared-clock-impl-handlers.c src/os-shared-clock-impl-stubs.c src/os-shared-common-impl-stubs.c src/os-shared-condvar-impl-stubs.c @@ -275,4 +276,3 @@ add_library(ut_bsp_impl_stubs STATIC EXCLUDE_FROM_ALL target_link_libraries(ut_bsp_impl_stubs PUBLIC ut_osapi_stub_headers ) - diff --git a/src/unit-test-coverage/ut-stubs/src/os-shared-clock-impl-handlers.c b/src/unit-test-coverage/ut-stubs/src/os-shared-clock-impl-handlers.c new file mode 100644 index 000000000..6eda3b25f --- /dev/null +++ b/src/unit-test-coverage/ut-stubs/src/os-shared-clock-impl-handlers.c @@ -0,0 +1,52 @@ +/************************************************************************ + * NASA Docket No. GSC-18,719-1, and identified as “core Flight System: Bootes” + * + * Copyright (c) 2020 United States Government as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ************************************************************************/ + +/** + * \file + * \author joseph.p.hickey@nasa.gov + * + * Stub implementations for the functions defined in the OSAL API + * + * The stub implementation can be used for unit testing applications built + * on top of OSAL. The stubs do not do any real function, but allow + * the return code to be crafted such that error paths in the application + * can be executed. + */ + +#include "osapi-clock.h" /* OSAL public API for this subsystem */ +#include "os-shared-clock.h" +#include "utstubs.h" + +/* + * ----------------------------------------------------------------- + * Default handler implementation for 'OS_GetLocalTime_Impl' stub + * ----------------------------------------------------------------- + */ +void UT_DefaultHandler_OS_GetLocalTime_Impl(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + OS_time_t *time_struct = UT_Hook_GetArgValueByName(Context, "time_struct", OS_time_t *); + int32 status; + + UT_Stub_GetInt32StatusCode(Context, &status); + + if (status == OS_SUCCESS && + UT_Stub_CopyToLocal(UT_KEY(OS_GetLocalTime_Impl), time_struct, sizeof(*time_struct)) < sizeof(*time_struct)) + { + memset(time_struct, 0, sizeof(*time_struct)); + } +} diff --git a/src/unit-test-coverage/ut-stubs/src/os-shared-clock-impl-stubs.c b/src/unit-test-coverage/ut-stubs/src/os-shared-clock-impl-stubs.c index 4e7c64470..e8f2160a2 100644 --- a/src/unit-test-coverage/ut-stubs/src/os-shared-clock-impl-stubs.c +++ b/src/unit-test-coverage/ut-stubs/src/os-shared-clock-impl-stubs.c @@ -25,6 +25,8 @@ #include "os-shared-clock.h" #include "utgenstub.h" +void UT_DefaultHandler_OS_GetLocalTime_Impl(void *, UT_EntryKey_t, const UT_StubContext_t *); + /* * ---------------------------------------------------- * Generated stub function for OS_GetLocalTime_Impl() @@ -36,7 +38,7 @@ int32 OS_GetLocalTime_Impl(OS_time_t *time_struct) UT_GenStub_AddParam(OS_GetLocalTime_Impl, OS_time_t *, time_struct); - UT_GenStub_Execute(OS_GetLocalTime_Impl, Basic, NULL); + UT_GenStub_Execute(OS_GetLocalTime_Impl, Basic, UT_DefaultHandler_OS_GetLocalTime_Impl); return UT_GenStub_GetReturnValue(OS_GetLocalTime_Impl, int32); } diff --git a/src/unit-test-coverage/ut-stubs/src/os-shared-file-impl-stubs.c b/src/unit-test-coverage/ut-stubs/src/os-shared-file-impl-stubs.c index 75c5bebf6..87c418997 100644 --- a/src/unit-test-coverage/ut-stubs/src/os-shared-file-impl-stubs.c +++ b/src/unit-test-coverage/ut-stubs/src/os-shared-file-impl-stubs.c @@ -135,14 +135,14 @@ int32 OS_GenericClose_Impl(const OS_object_token_t *token) * Generated stub function for OS_GenericRead_Impl() * ---------------------------------------------------- */ -int32 OS_GenericRead_Impl(const OS_object_token_t *token, void *buffer, size_t nbytes, int32 timeout) +int32 OS_GenericRead_Impl(const OS_object_token_t *token, void *buffer, size_t nbytes, OS_time_t abs_timeout) { UT_GenStub_SetupReturnBuffer(OS_GenericRead_Impl, int32); UT_GenStub_AddParam(OS_GenericRead_Impl, const OS_object_token_t *, token); UT_GenStub_AddParam(OS_GenericRead_Impl, void *, buffer); UT_GenStub_AddParam(OS_GenericRead_Impl, size_t, nbytes); - UT_GenStub_AddParam(OS_GenericRead_Impl, int32, timeout); + UT_GenStub_AddParam(OS_GenericRead_Impl, OS_time_t, abs_timeout); UT_GenStub_Execute(OS_GenericRead_Impl, Basic, UT_DefaultHandler_OS_GenericRead_Impl); @@ -172,14 +172,14 @@ int32 OS_GenericSeek_Impl(const OS_object_token_t *token, int32 offset, uint32 w * Generated stub function for OS_GenericWrite_Impl() * ---------------------------------------------------- */ -int32 OS_GenericWrite_Impl(const OS_object_token_t *token, const void *buffer, size_t nbytes, int32 timeout) +int32 OS_GenericWrite_Impl(const OS_object_token_t *token, const void *buffer, size_t nbytes, OS_time_t abs_timeout) { UT_GenStub_SetupReturnBuffer(OS_GenericWrite_Impl, int32); UT_GenStub_AddParam(OS_GenericWrite_Impl, const OS_object_token_t *, token); UT_GenStub_AddParam(OS_GenericWrite_Impl, const void *, buffer); UT_GenStub_AddParam(OS_GenericWrite_Impl, size_t, nbytes); - UT_GenStub_AddParam(OS_GenericWrite_Impl, int32, timeout); + UT_GenStub_AddParam(OS_GenericWrite_Impl, OS_time_t, abs_timeout); UT_GenStub_Execute(OS_GenericWrite_Impl, Basic, UT_DefaultHandler_OS_GenericWrite_Impl); diff --git a/src/unit-test-coverage/ut-stubs/src/os-shared-select-impl-stubs.c b/src/unit-test-coverage/ut-stubs/src/os-shared-select-impl-stubs.c index e166537d2..9ba9a554d 100644 --- a/src/unit-test-coverage/ut-stubs/src/os-shared-select-impl-stubs.c +++ b/src/unit-test-coverage/ut-stubs/src/os-shared-select-impl-stubs.c @@ -30,13 +30,13 @@ * Generated stub function for OS_SelectMultiple_Impl() * ---------------------------------------------------- */ -int32 OS_SelectMultiple_Impl(OS_FdSet *ReadSet, OS_FdSet *WriteSet, int32 msecs) +int32 OS_SelectMultiple_Impl(OS_FdSet *ReadSet, OS_FdSet *WriteSet, OS_time_t abs_timeout) { UT_GenStub_SetupReturnBuffer(OS_SelectMultiple_Impl, int32); UT_GenStub_AddParam(OS_SelectMultiple_Impl, OS_FdSet *, ReadSet); UT_GenStub_AddParam(OS_SelectMultiple_Impl, OS_FdSet *, WriteSet); - UT_GenStub_AddParam(OS_SelectMultiple_Impl, int32, msecs); + UT_GenStub_AddParam(OS_SelectMultiple_Impl, OS_time_t, abs_timeout); UT_GenStub_Execute(OS_SelectMultiple_Impl, Basic, NULL); @@ -48,13 +48,13 @@ int32 OS_SelectMultiple_Impl(OS_FdSet *ReadSet, OS_FdSet *WriteSet, int32 msecs) * Generated stub function for OS_SelectSingle_Impl() * ---------------------------------------------------- */ -int32 OS_SelectSingle_Impl(const OS_object_token_t *token, uint32 *SelectFlags, int32 msecs) +int32 OS_SelectSingle_Impl(const OS_object_token_t *token, uint32 *SelectFlags, OS_time_t abs_timeout) { UT_GenStub_SetupReturnBuffer(OS_SelectSingle_Impl, int32); UT_GenStub_AddParam(OS_SelectSingle_Impl, const OS_object_token_t *, token); UT_GenStub_AddParam(OS_SelectSingle_Impl, uint32 *, SelectFlags); - UT_GenStub_AddParam(OS_SelectSingle_Impl, int32, msecs); + UT_GenStub_AddParam(OS_SelectSingle_Impl, OS_time_t, abs_timeout); UT_GenStub_Execute(OS_SelectSingle_Impl, Basic, NULL); diff --git a/src/unit-test-coverage/ut-stubs/src/os-shared-sockets-impl-stubs.c b/src/unit-test-coverage/ut-stubs/src/os-shared-sockets-impl-stubs.c index 5ec3ea0f9..5e258b095 100644 --- a/src/unit-test-coverage/ut-stubs/src/os-shared-sockets-impl-stubs.c +++ b/src/unit-test-coverage/ut-stubs/src/os-shared-sockets-impl-stubs.c @@ -45,14 +45,14 @@ void OS_SetSocketDefaultFlags_Impl(const OS_object_token_t *token) * ---------------------------------------------------- */ int32 OS_SocketAccept_Impl(const OS_object_token_t *sock_token, const OS_object_token_t *conn_token, - OS_SockAddr_t *Addr, int32 timeout) + OS_SockAddr_t *Addr, OS_time_t abs_timeout) { UT_GenStub_SetupReturnBuffer(OS_SocketAccept_Impl, int32); UT_GenStub_AddParam(OS_SocketAccept_Impl, const OS_object_token_t *, sock_token); UT_GenStub_AddParam(OS_SocketAccept_Impl, const OS_object_token_t *, conn_token); UT_GenStub_AddParam(OS_SocketAccept_Impl, OS_SockAddr_t *, Addr); - UT_GenStub_AddParam(OS_SocketAccept_Impl, int32, timeout); + UT_GenStub_AddParam(OS_SocketAccept_Impl, OS_time_t, abs_timeout); UT_GenStub_Execute(OS_SocketAccept_Impl, Basic, NULL); @@ -167,13 +167,13 @@ int32 OS_SocketBindAddress_Impl(const OS_object_token_t *token, const OS_SockAdd * Generated stub function for OS_SocketConnect_Impl() * ---------------------------------------------------- */ -int32 OS_SocketConnect_Impl(const OS_object_token_t *token, const OS_SockAddr_t *Addr, int32 timeout) +int32 OS_SocketConnect_Impl(const OS_object_token_t *token, const OS_SockAddr_t *Addr, OS_time_t abs_timeout) { UT_GenStub_SetupReturnBuffer(OS_SocketConnect_Impl, int32); UT_GenStub_AddParam(OS_SocketConnect_Impl, const OS_object_token_t *, token); UT_GenStub_AddParam(OS_SocketConnect_Impl, const OS_SockAddr_t *, Addr); - UT_GenStub_AddParam(OS_SocketConnect_Impl, int32, timeout); + UT_GenStub_AddParam(OS_SocketConnect_Impl, OS_time_t, abs_timeout); UT_GenStub_Execute(OS_SocketConnect_Impl, Basic, NULL); @@ -235,7 +235,7 @@ int32 OS_SocketOpen_Impl(const OS_object_token_t *token) * ---------------------------------------------------- */ int32 OS_SocketRecvFrom_Impl(const OS_object_token_t *token, void *buffer, size_t buflen, OS_SockAddr_t *RemoteAddr, - int32 timeout) + OS_time_t abs_timeout) { UT_GenStub_SetupReturnBuffer(OS_SocketRecvFrom_Impl, int32); @@ -243,7 +243,7 @@ int32 OS_SocketRecvFrom_Impl(const OS_object_token_t *token, void *buffer, size_ UT_GenStub_AddParam(OS_SocketRecvFrom_Impl, void *, buffer); UT_GenStub_AddParam(OS_SocketRecvFrom_Impl, size_t, buflen); UT_GenStub_AddParam(OS_SocketRecvFrom_Impl, OS_SockAddr_t *, RemoteAddr); - UT_GenStub_AddParam(OS_SocketRecvFrom_Impl, int32, timeout); + UT_GenStub_AddParam(OS_SocketRecvFrom_Impl, OS_time_t, abs_timeout); UT_GenStub_Execute(OS_SocketRecvFrom_Impl, Basic, NULL); diff --git a/src/ut-stubs/osapi-clock-stubs.c b/src/ut-stubs/osapi-clock-stubs.c index 4d3b11bc8..27914ea91 100644 --- a/src/ut-stubs/osapi-clock-stubs.c +++ b/src/ut-stubs/osapi-clock-stubs.c @@ -59,3 +59,35 @@ int32 OS_SetLocalTime(const OS_time_t *time_struct) return UT_GenStub_GetReturnValue(OS_SetLocalTime, int32); } + +/* + * ---------------------------------------------------- + * Generated stub function for OS_TimeFromRelativeMilliseconds() + * ---------------------------------------------------- + */ +OS_time_t OS_TimeFromRelativeMilliseconds(int32 relative_msec) +{ + UT_GenStub_SetupReturnBuffer(OS_TimeFromRelativeMilliseconds, OS_time_t); + + UT_GenStub_AddParam(OS_TimeFromRelativeMilliseconds, int32, relative_msec); + + UT_GenStub_Execute(OS_TimeFromRelativeMilliseconds, Basic, NULL); + + return UT_GenStub_GetReturnValue(OS_TimeFromRelativeMilliseconds, OS_time_t); +} + +/* + * ---------------------------------------------------- + * Generated stub function for OS_TimeToRelativeMilliseconds() + * ---------------------------------------------------- + */ +int32 OS_TimeToRelativeMilliseconds(OS_time_t time) +{ + UT_GenStub_SetupReturnBuffer(OS_TimeToRelativeMilliseconds, int32); + + UT_GenStub_AddParam(OS_TimeToRelativeMilliseconds, OS_time_t, time); + + UT_GenStub_Execute(OS_TimeToRelativeMilliseconds, Basic, NULL); + + return UT_GenStub_GetReturnValue(OS_TimeToRelativeMilliseconds, int32); +} diff --git a/src/ut-stubs/osapi-file-stubs.c b/src/ut-stubs/osapi-file-stubs.c index de52a1570..a25c8eacb 100644 --- a/src/ut-stubs/osapi-file-stubs.c +++ b/src/ut-stubs/osapi-file-stubs.c @@ -35,6 +35,44 @@ void UT_DefaultHandler_OS_read(void *, UT_EntryKey_t, const UT_StubContext_t *); void UT_DefaultHandler_OS_stat(void *, UT_EntryKey_t, const UT_StubContext_t *); void UT_DefaultHandler_OS_write(void *, UT_EntryKey_t, const UT_StubContext_t *); +/* + * ---------------------------------------------------- + * Generated stub function for OS_TimedReadAbs() + * ---------------------------------------------------- + */ +int32 OS_TimedReadAbs(osal_id_t filedes, void *buffer, size_t nbytes, OS_time_t abstime) +{ + UT_GenStub_SetupReturnBuffer(OS_TimedReadAbs, int32); + + UT_GenStub_AddParam(OS_TimedReadAbs, osal_id_t, filedes); + UT_GenStub_AddParam(OS_TimedReadAbs, void *, buffer); + UT_GenStub_AddParam(OS_TimedReadAbs, size_t, nbytes); + UT_GenStub_AddParam(OS_TimedReadAbs, OS_time_t, abstime); + + UT_GenStub_Execute(OS_TimedReadAbs, Basic, NULL); + + return UT_GenStub_GetReturnValue(OS_TimedReadAbs, int32); +} + +/* + * ---------------------------------------------------- + * Generated stub function for OS_TimedWriteAbs() + * ---------------------------------------------------- + */ +int32 OS_TimedWriteAbs(osal_id_t filedes, const void *buffer, size_t nbytes, OS_time_t abstime) +{ + UT_GenStub_SetupReturnBuffer(OS_TimedWriteAbs, int32); + + UT_GenStub_AddParam(OS_TimedWriteAbs, osal_id_t, filedes); + UT_GenStub_AddParam(OS_TimedWriteAbs, const void *, buffer); + UT_GenStub_AddParam(OS_TimedWriteAbs, size_t, nbytes); + UT_GenStub_AddParam(OS_TimedWriteAbs, OS_time_t, abstime); + + UT_GenStub_Execute(OS_TimedWriteAbs, Basic, NULL); + + return UT_GenStub_GetReturnValue(OS_TimedWriteAbs, int32); +} + /* * ---------------------------------------------------- * Generated stub function for OS_CloseAllFiles() diff --git a/src/ut-stubs/osapi-sockets-stubs.c b/src/ut-stubs/osapi-sockets-stubs.c index d8676076a..b61d3f017 100644 --- a/src/ut-stubs/osapi-sockets-stubs.c +++ b/src/ut-stubs/osapi-sockets-stubs.c @@ -280,6 +280,27 @@ int32 OS_SocketRecvFrom(osal_id_t sock_id, void *buffer, size_t buflen, OS_SockA return UT_GenStub_GetReturnValue(OS_SocketRecvFrom, int32); } +/* + * ---------------------------------------------------- + * Generated stub function for OS_SocketRecvFromAbs() + * ---------------------------------------------------- + */ +int32 OS_SocketRecvFromAbs(osal_id_t sock_id, void *buffer, size_t buflen, OS_SockAddr_t *RemoteAddr, + OS_time_t abs_timeout) +{ + UT_GenStub_SetupReturnBuffer(OS_SocketRecvFromAbs, int32); + + UT_GenStub_AddParam(OS_SocketRecvFromAbs, osal_id_t, sock_id); + UT_GenStub_AddParam(OS_SocketRecvFromAbs, void *, buffer); + UT_GenStub_AddParam(OS_SocketRecvFromAbs, size_t, buflen); + UT_GenStub_AddParam(OS_SocketRecvFromAbs, OS_SockAddr_t *, RemoteAddr); + UT_GenStub_AddParam(OS_SocketRecvFromAbs, OS_time_t, abs_timeout); + + UT_GenStub_Execute(OS_SocketRecvFromAbs, Basic, NULL); + + return UT_GenStub_GetReturnValue(OS_SocketRecvFromAbs, int32); +} + /* * ---------------------------------------------------- * Generated stub function for OS_SocketSendTo() From 3b40ede1b877ffd5356532ffd35d9bebb3d782cf Mon Sep 17 00:00:00 2001 From: jdfiguer Date: Thu, 13 Jun 2024 13:07:50 -0400 Subject: [PATCH 2/5] Fix #1458, Moves OS_strnlen to public API and adds static analysis comments This commit addresses issues flagged during static analysis by: - Adding JSC 2.1 disposition comments. - Making OS_strnlen publicly accessible and replacing strlen with it. --- src/os/inc/osapi-clock.h | 1 + src/os/inc/osapi-common.h | 15 ++++++ src/os/shared/inc/os-shared-common.h | 21 -------- src/os/shared/src/osapi-common.c | 17 ++++++ src/os/shared/src/osapi-condvar.c | 4 +- src/os/shared/src/osapi-errors.c | 3 +- .../shared/src/coveragetest-common.c | 23 ++++++++ .../shared/src/coveragetest-filesys.c | 53 ++++++++++++++++++- .../shared/src/coveragetest-idmap.c | 1 + src/ut-stubs/osapi-common-stubs.c | 17 ++++++ 10 files changed, 131 insertions(+), 24 deletions(-) diff --git a/src/os/inc/osapi-clock.h b/src/os/inc/osapi-clock.h index 50cc82c6d..ae059e6c3 100644 --- a/src/os/inc/osapi-clock.h +++ b/src/os/inc/osapi-clock.h @@ -215,6 +215,7 @@ static inline int64 OS_TimeGetTotalMicroseconds(OS_time_t tm) */ static inline OS_time_t OS_TimeFromTotalMicroseconds(int64 tm) { + /* SAD: Overflow is not considered a concern because tm would need to be over 29,227 years in microseconds */ OS_time_t ostm = {tm * OS_TIME_TICKS_PER_USEC}; return ostm; } diff --git a/src/os/inc/osapi-common.h b/src/os/inc/osapi-common.h index cc1f24549..55ed74372 100644 --- a/src/os/inc/osapi-common.h +++ b/src/os/inc/osapi-common.h @@ -233,6 +233,21 @@ void OS_ApplicationExit(int32 Status); */ int32 OS_RegisterEventHandler(OS_EventHandler_t handler); +/*-------------------------------------------------------------------------------------*/ +/** + * @brief get string length + * + * Provides an OSAL routine to get the functionality + * of the (non-C99) "strnlen()" function, via the + * C89/C99 standard "memchr()" function instead. + * + * @param[in] s The input string + * @param[in] maxlen Maximum length to check + * @retval Length of the string or maxlen, whichever is smaller. + + */ +size_t OS_strnlen(const char *s, size_t maxlen); + /**@}*/ #endif /* OSAPI_COMMON_H */ diff --git a/src/os/shared/inc/os-shared-common.h b/src/os/shared/inc/os-shared-common.h index e84249835..e602e8f87 100644 --- a/src/os/shared/inc/os-shared-common.h +++ b/src/os/shared/inc/os-shared-common.h @@ -129,25 +129,4 @@ void OS_IdleLoop_Impl(void); ------------------------------------------------------------------*/ void OS_ApplicationShutdown_Impl(void); -/*---------------------------------------------------------------- - - Purpose: Utility function to safely find the length of a string - within a fixed-size array buffer. - - Provides a local OSAL routine to get the functionality - of the (non-C99) "strnlen()" function, via the - C89/C99 standard "memchr()" function instead. - - ------------------------------------------------------------------*/ -static inline size_t OS_strnlen(const char *s, size_t maxlen) -{ - const char *end = (const char *)memchr(s, 0, maxlen); - if (end != NULL) - { - /* actual length of string is difference */ - maxlen = end - s; - } - return maxlen; -} - #endif /* OS_SHARED_COMMON_H */ diff --git a/src/os/shared/src/osapi-common.c b/src/os/shared/src/osapi-common.c index 6e13a7170..c669ed594 100644 --- a/src/os/shared/src/osapi-common.c +++ b/src/os/shared/src/osapi-common.c @@ -423,3 +423,20 @@ void OS_ApplicationShutdown(uint8 flag) */ OS_ApplicationShutdown_Impl(); } + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +size_t OS_strnlen(const char *s, size_t maxlen) +{ + const char *end = (const char *)memchr(s, 0, maxlen); + if (end != NULL) + { + /* actual length of string is difference */ + maxlen = end - s; + } + return maxlen; +} diff --git a/src/os/shared/src/osapi-condvar.c b/src/os/shared/src/osapi-condvar.c index 1407c5262..4bed5c7a6 100644 --- a/src/os/shared/src/osapi-condvar.c +++ b/src/os/shared/src/osapi-condvar.c @@ -66,6 +66,7 @@ OS_condvar_internal_record_t OS_condvar_table[OS_MAX_CONDVARS]; *-----------------------------------------------------------------*/ int32 OS_CondVarAPI_Init(void) { + // SAD: Using memset as sizeof(OS_condvar_table) ensures correct array size memset(OS_condvar_table, 0, sizeof(OS_condvar_table)); return OS_SUCCESS; } @@ -291,6 +292,7 @@ int32 OS_CondVarGetInfo(osal_id_t var_id, OS_condvar_prop_t *condvar_prop) /* Check parameters */ OS_CHECK_POINTER(condvar_prop); + // SAD: Using memset as sizeof(OS_condvar_prop_t) ensures correct array size memset(condvar_prop, 0, sizeof(OS_condvar_prop_t)); return_code = OS_ObjectIdGetById(OS_LOCK_MODE_GLOBAL, OS_OBJECT_TYPE_OS_CONDVAR, var_id, &token); @@ -298,7 +300,7 @@ int32 OS_CondVarGetInfo(osal_id_t var_id, OS_condvar_prop_t *condvar_prop) { record = OS_OBJECT_TABLE_GET(OS_global_condvar_table, token); - strncpy(condvar_prop->name, record->name_entry, sizeof(condvar_prop->name) - 1); + snprintf(condvar_prop->name, sizeof(condvar_prop->name), "%s", record->name_entry); condvar_prop->creator = record->creator; return_code = OS_CondVarGetInfo_Impl(&token, condvar_prop); diff --git a/src/os/shared/src/osapi-errors.c b/src/os/shared/src/osapi-errors.c index 41573bd4c..4a915a793 100644 --- a/src/os/shared/src/osapi-errors.c +++ b/src/os/shared/src/osapi-errors.c @@ -110,6 +110,7 @@ char *OS_StatusToString(osal_status_t status, os_status_string_t *status_string) if (status_string != NULL) { + // SAD: No need to check snprintf return; OS_STATUS_STRING_LENGTH (12) is ample for all status values snprintf(*status_string, sizeof(*status_string), "%ld", OS_StatusToInteger(status)); string = *status_string; } @@ -149,7 +150,7 @@ int32 OS_GetErrorName(int32 error_num, os_err_name_t *err_name) { strncpy(*err_name, Error->Name, sizeof(*err_name) - 1); (*err_name)[sizeof(*err_name) - 1] = 0; - return_code = OS_SUCCESS; + return_code = OS_SUCCESS; } else { diff --git a/src/unit-test-coverage/shared/src/coveragetest-common.c b/src/unit-test-coverage/shared/src/coveragetest-common.c index 8ee1b8986..f42b2e789 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-common.c +++ b/src/unit-test-coverage/shared/src/coveragetest-common.c @@ -332,6 +332,28 @@ void Test_OS_NotifyEvent(void) OS_SharedGlobalVars.EventHandler = NULL; } +void Test_OS_strnlen(void) +{ + + size_t result; + char str[OS_MAX_FILE_NAME]; + + memset(str, 0xFF, sizeof(str)); + + /* Test case where null character is not found */ + result = OS_strnlen(str, sizeof(str)); + + UtAssert_INT32_EQ(result, sizeof(str)); + + + /* Test case where null character is found */ + str[OS_MAX_FILE_NAME - 1] = '\0'; + + result = OS_strnlen(str, sizeof(str)); + + UtAssert_INT32_EQ(result, sizeof(str) - 1); +} + /* ------------------- End of test cases --------------------------------------*/ /* Osapi_Test_Setup @@ -364,4 +386,5 @@ void UtTest_Setup(void) ADD_TEST(OS_ApplicationExit); ADD_TEST(OS_NotifyEvent); ADD_TEST(OS_API_Teardown); + ADD_TEST(OS_strnlen); } diff --git a/src/unit-test-coverage/shared/src/coveragetest-filesys.c b/src/unit-test-coverage/shared/src/coveragetest-filesys.c index 551b00fd0..56e8b47c5 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-filesys.c +++ b/src/unit-test-coverage/shared/src/coveragetest-filesys.c @@ -410,6 +410,7 @@ void Test_OS_TranslatePath(void) * int32 OS_TranslatePath(const char *VirtualPath, char *LocalPath) */ char LocalBuffer[OS_MAX_PATH_LEN]; + char DoubleBuffer[2 * OS_MAX_PATH_LEN]; int32 expected = OS_SUCCESS; int32 actual = ~OS_SUCCESS; @@ -421,37 +422,68 @@ void Test_OS_TranslatePath(void) strcpy(OS_filesys_table[1].virtual_mountpt, "/cf"); strcpy(OS_filesys_table[1].system_mountpt, "/mnt/cf"); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_SUCCESS", (long)actual); UtAssert_True(strcmp(LocalBuffer, "/mnt/cf/test") == 0, "OS_TranslatePath(/cf/test) (%s) == /mnt/cf/test", LocalBuffer); + /* VirtPathLen >= OS_MAX_PATH_LEN */ + memset(DoubleBuffer, 0xFF, sizeof(DoubleBuffer) - 1); + DoubleBuffer[sizeof(DoubleBuffer) - 1] = '\0'; + UT_ResetState(UT_KEY(OS_strnlen)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(DoubleBuffer)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); + OSAPI_TEST_FUNCTION_RC(OS_TranslatePath(DoubleBuffer, LocalBuffer), OS_FS_ERR_PATH_TOO_LONG); + /* Check various error paths */ UtAssert_INT32_EQ(OS_TranslatePath("/cf/test", NULL), OS_INVALID_POINTER); UtAssert_INT32_EQ(OS_TranslatePath(NULL, LocalBuffer), OS_INVALID_POINTER); UT_SetDefaultReturnValue(UT_KEY(OCS_memchr), OS_ERROR); expected = OS_FS_ERR_PATH_TOO_LONG; + UT_ResetState(UT_KEY(OS_strnlen)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath() (%ld) == OS_FS_ERR_PATH_TOO_LONG", (long)actual); - UT_ClearDefaultReturnValue(UT_KEY(OCS_memchr)); /* Invalid no '/' */ expected = OS_FS_ERR_PATH_INVALID; + UT_ResetState(UT_KEY(OS_strnlen)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("invalid/")); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("invalid", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath() (%ld) == OS_FS_ERR_PATH_INVALID", (long)actual); UT_SetDeferredRetcode(UT_KEY(OCS_memchr), 2, OS_ERROR); expected = OS_FS_ERR_NAME_TOO_LONG; + UT_ResetState(UT_KEY(OS_strnlen)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_FS_ERR_NAME_TOO_LONG", (long)actual); /* Invalid no leading '/' */ expected = OS_FS_ERR_PATH_INVALID; + UT_ResetState(UT_KEY(OS_strnlen)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("invalid/")); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("invalid/", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath() (%ld) == OS_FS_ERR_PATH_INVALID", (long)actual); UT_SetDefaultReturnValue(UT_KEY(OS_ObjectIdGetBySearch), OS_ERR_NAME_NOT_FOUND); + UT_ResetState(UT_KEY(OS_strnlen)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath() (%ld) == OS_FS_ERR_PATH_INVALID", (long)actual); UT_ClearDefaultReturnValue(UT_KEY(OS_ObjectIdGetBySearch)); @@ -459,17 +491,29 @@ void Test_OS_TranslatePath(void) /* VirtPathLen < VirtPathBegin */ UT_SetDeferredRetcode(UT_KEY(OCS_memchr), 4, OS_ERROR); expected = OS_FS_ERR_PATH_INVALID; + UT_ResetState(UT_KEY(OS_strnlen)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_FS_ERR_PATH_INVALID", (long)actual); /* (SysMountPointLen + VirtPathLen) > OS_MAX_LOCAL_PATH_LEN */ UT_SetDeferredRetcode(UT_KEY(OCS_memchr), 3, OS_ERROR); expected = OS_FS_ERR_PATH_TOO_LONG; + UT_ResetState(UT_KEY(OS_strnlen)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_FS_ERR_PATH_TOO_LONG", (long)actual); OS_filesys_table[1].flags = 0; expected = OS_ERR_INCORRECT_OBJ_STATE; + UT_ResetState(UT_KEY(OS_strnlen)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_ERR_INCORRECT_OBJ_STATE", (long)actual); } @@ -497,17 +541,20 @@ void Test_OS_FileSys_FindVirtMountPoint(void) OS_filesys_table[1].flags = 0; OS_filesys_table[1].virtual_mountpt[0] = 0; + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (unmounted) == false", refstr); OS_filesys_table[1].flags = OS_FILESYS_FLAG_IS_MOUNTED_VIRTUAL; /* Branch coverage for mismatches */ + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (mountpt=%s) == false", refstr, OS_filesys_table[1].virtual_mountpt); memset(OS_filesys_table[1].virtual_mountpt, 'a', sizeof(OS_filesys_table[1].virtual_mountpt)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (mountpt=%s) == false", refstr, OS_filesys_table[1].virtual_mountpt); @@ -515,21 +562,25 @@ void Test_OS_FileSys_FindVirtMountPoint(void) /* Verify cases where one is a substring of the other - * these should also return false */ strncpy(OS_filesys_table[1].virtual_mountpt, "/ut11", sizeof(OS_filesys_table[1].virtual_mountpt)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (mountpt=%s) == false", refstr, OS_filesys_table[1].virtual_mountpt); strncpy(OS_filesys_table[1].virtual_mountpt, "/u", sizeof(OS_filesys_table[1].virtual_mountpt)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (mountpt=%s) == false", refstr, OS_filesys_table[1].virtual_mountpt); strncpy(OS_filesys_table[1].virtual_mountpt, "/ut", sizeof(OS_filesys_table[1].virtual_mountpt)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(result, "OS_FileSys_FindVirtMountPoint(%s) (nominal) == true", refstr); /* Passing case with reference ending in "/" */ strncpy(OS_filesys_table[1].virtual_mountpt, "/ut", sizeof(OS_filesys_table[1].virtual_mountpt)); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr1, &token, &refobj); UtAssert_True(result, "OS_FileSys_FindVirtMountPoint(%s) (nominal) == true", refstr); } diff --git a/src/unit-test-coverage/shared/src/coveragetest-idmap.c b/src/unit-test-coverage/shared/src/coveragetest-idmap.c index 1b8f8ea8a..100108a7d 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-idmap.c +++ b/src/unit-test-coverage/shared/src/coveragetest-idmap.c @@ -1087,6 +1087,7 @@ void Test_OS_GetResourceName(void) OSAPI_TEST_FUNCTION_RC(OS_GetResourceName(token.obj_id, NameBuffer, sizeof(NameBuffer)), OS_SUCCESS); UtAssert_True(strcmp(NameBuffer, "UTTask") == 0, "NameBuffer (%s) == UTTask", NameBuffer); + UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(rptr->name_entry)); OSAPI_TEST_FUNCTION_RC(OS_GetResourceName(token.obj_id, NameBuffer, OSAL_SIZE_C(2)), OS_ERR_NAME_TOO_LONG); /* Null entry */ diff --git a/src/ut-stubs/osapi-common-stubs.c b/src/ut-stubs/osapi-common-stubs.c index d3e85afb6..acb87a579 100644 --- a/src/ut-stubs/osapi-common-stubs.c +++ b/src/ut-stubs/osapi-common-stubs.c @@ -111,3 +111,20 @@ int32 OS_RegisterEventHandler(OS_EventHandler_t handler) return UT_GenStub_GetReturnValue(OS_RegisterEventHandler, int32); } + +/* + * ---------------------------------------------------- + * Generated stub function for OS_strnlen() + * ---------------------------------------------------- + */ +size_t OS_strnlen(const char *s, size_t maxlen) +{ + UT_GenStub_SetupReturnBuffer(OS_strnlen, size_t); + + UT_GenStub_AddParam(OS_strnlen, const char *, s); + UT_GenStub_AddParam(OS_strnlen, size_t, maxlen); + + UT_GenStub_Execute(OS_strnlen, Basic, NULL); + + return UT_GenStub_GetReturnValue(OS_strnlen, size_t); +} From 44763aa5d207b8b1aa4af28ce94f80d9313a272a Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Mon, 24 Jun 2024 18:21:06 -0400 Subject: [PATCH 3/5] Fix #1465, add default handler for OS_strnlen Calls to "OS_strnlen" are likely needed to return an actual length, so make a default handler that does return a length. The value may still be overridden in tests, though. --- .../shared/src/coveragetest-common.c | 1 - .../shared/src/coveragetest-filesys.c | 63 ++-------------- .../shared/src/coveragetest-idmap.c | 1 - src/ut-stubs/CMakeLists.txt | 1 + src/ut-stubs/osapi-common-handlers.c | 72 +++++++++++++++++++ src/ut-stubs/osapi-common-stubs.c | 4 +- 6 files changed, 82 insertions(+), 60 deletions(-) create mode 100644 src/ut-stubs/osapi-common-handlers.c diff --git a/src/unit-test-coverage/shared/src/coveragetest-common.c b/src/unit-test-coverage/shared/src/coveragetest-common.c index f42b2e789..271b30744 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-common.c +++ b/src/unit-test-coverage/shared/src/coveragetest-common.c @@ -345,7 +345,6 @@ void Test_OS_strnlen(void) UtAssert_INT32_EQ(result, sizeof(str)); - /* Test case where null character is found */ str[OS_MAX_FILE_NAME - 1] = '\0'; diff --git a/src/unit-test-coverage/shared/src/coveragetest-filesys.c b/src/unit-test-coverage/shared/src/coveragetest-filesys.c index 56e8b47c5..3ba4f14a1 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-filesys.c +++ b/src/unit-test-coverage/shared/src/coveragetest-filesys.c @@ -410,7 +410,6 @@ void Test_OS_TranslatePath(void) * int32 OS_TranslatePath(const char *VirtualPath, char *LocalPath) */ char LocalBuffer[OS_MAX_PATH_LEN]; - char DoubleBuffer[2 * OS_MAX_PATH_LEN]; int32 expected = OS_SUCCESS; int32 actual = ~OS_SUCCESS; @@ -422,98 +421,55 @@ void Test_OS_TranslatePath(void) strcpy(OS_filesys_table[1].virtual_mountpt, "/cf"); strcpy(OS_filesys_table[1].system_mountpt, "/mnt/cf"); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_SUCCESS", (long)actual); UtAssert_True(strcmp(LocalBuffer, "/mnt/cf/test") == 0, "OS_TranslatePath(/cf/test) (%s) == /mnt/cf/test", LocalBuffer); - /* VirtPathLen >= OS_MAX_PATH_LEN */ - memset(DoubleBuffer, 0xFF, sizeof(DoubleBuffer) - 1); - DoubleBuffer[sizeof(DoubleBuffer) - 1] = '\0'; - UT_ResetState(UT_KEY(OS_strnlen)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(DoubleBuffer)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); - OSAPI_TEST_FUNCTION_RC(OS_TranslatePath(DoubleBuffer, LocalBuffer), OS_FS_ERR_PATH_TOO_LONG); - /* Check various error paths */ UtAssert_INT32_EQ(OS_TranslatePath("/cf/test", NULL), OS_INVALID_POINTER); UtAssert_INT32_EQ(OS_TranslatePath(NULL, LocalBuffer), OS_INVALID_POINTER); - UT_SetDefaultReturnValue(UT_KEY(OCS_memchr), OS_ERROR); expected = OS_FS_ERR_PATH_TOO_LONG; - UT_ResetState(UT_KEY(OS_strnlen)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); - actual = OS_TranslatePath("/cf/test", LocalBuffer); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 1, OS_MAX_PATH_LEN + 1); + actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath() (%ld) == OS_FS_ERR_PATH_TOO_LONG", (long)actual); + UT_ResetState(UT_KEY(OS_strnlen)); /* Invalid no '/' */ expected = OS_FS_ERR_PATH_INVALID; - UT_ResetState(UT_KEY(OS_strnlen)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("invalid/")); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("invalid", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath() (%ld) == OS_FS_ERR_PATH_INVALID", (long)actual); - UT_SetDeferredRetcode(UT_KEY(OCS_memchr), 2, OS_ERROR); + UT_SetDeferredRetcode(UT_KEY(OCS_memchr), 1, OS_ERROR); expected = OS_FS_ERR_NAME_TOO_LONG; - UT_ResetState(UT_KEY(OS_strnlen)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_FS_ERR_NAME_TOO_LONG", (long)actual); /* Invalid no leading '/' */ expected = OS_FS_ERR_PATH_INVALID; - UT_ResetState(UT_KEY(OS_strnlen)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("invalid/")); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("invalid/", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath() (%ld) == OS_FS_ERR_PATH_INVALID", (long)actual); UT_SetDefaultReturnValue(UT_KEY(OS_ObjectIdGetBySearch), OS_ERR_NAME_NOT_FOUND); - UT_ResetState(UT_KEY(OS_strnlen)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath() (%ld) == OS_FS_ERR_PATH_INVALID", (long)actual); UT_ClearDefaultReturnValue(UT_KEY(OS_ObjectIdGetBySearch)); /* VirtPathLen < VirtPathBegin */ - UT_SetDeferredRetcode(UT_KEY(OCS_memchr), 4, OS_ERROR); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 1, 1); expected = OS_FS_ERR_PATH_INVALID; - UT_ResetState(UT_KEY(OS_strnlen)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_FS_ERR_PATH_INVALID", (long)actual); /* (SysMountPointLen + VirtPathLen) > OS_MAX_LOCAL_PATH_LEN */ - UT_SetDeferredRetcode(UT_KEY(OCS_memchr), 3, OS_ERROR); + UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, OS_MAX_LOCAL_PATH_LEN + 1); expected = OS_FS_ERR_PATH_TOO_LONG; - UT_ResetState(UT_KEY(OS_strnlen)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_FS_ERR_PATH_TOO_LONG", (long)actual); OS_filesys_table[1].flags = 0; expected = OS_ERR_INCORRECT_OBJ_STATE; - UT_ResetState(UT_KEY(OS_strnlen)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen("/cf/test")); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 2, strlen(OS_filesys_table[1].system_mountpt)); - UT_SetDeferredRetcode(UT_KEY(OS_strnlen), 3, strlen(OS_filesys_table[1].virtual_mountpt)); actual = OS_TranslatePath("/cf/test", LocalBuffer); UtAssert_True(actual == expected, "OS_TranslatePath(/cf/test) (%ld) == OS_ERR_INCORRECT_OBJ_STATE", (long)actual); } @@ -541,20 +497,17 @@ void Test_OS_FileSys_FindVirtMountPoint(void) OS_filesys_table[1].flags = 0; OS_filesys_table[1].virtual_mountpt[0] = 0; - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (unmounted) == false", refstr); OS_filesys_table[1].flags = OS_FILESYS_FLAG_IS_MOUNTED_VIRTUAL; /* Branch coverage for mismatches */ - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (mountpt=%s) == false", refstr, OS_filesys_table[1].virtual_mountpt); memset(OS_filesys_table[1].virtual_mountpt, 'a', sizeof(OS_filesys_table[1].virtual_mountpt)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (mountpt=%s) == false", refstr, OS_filesys_table[1].virtual_mountpt); @@ -562,25 +515,21 @@ void Test_OS_FileSys_FindVirtMountPoint(void) /* Verify cases where one is a substring of the other - * these should also return false */ strncpy(OS_filesys_table[1].virtual_mountpt, "/ut11", sizeof(OS_filesys_table[1].virtual_mountpt)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (mountpt=%s) == false", refstr, OS_filesys_table[1].virtual_mountpt); strncpy(OS_filesys_table[1].virtual_mountpt, "/u", sizeof(OS_filesys_table[1].virtual_mountpt)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(!result, "OS_FileSys_FindVirtMountPoint(%s) (mountpt=%s) == false", refstr, OS_filesys_table[1].virtual_mountpt); strncpy(OS_filesys_table[1].virtual_mountpt, "/ut", sizeof(OS_filesys_table[1].virtual_mountpt)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr, &token, &refobj); UtAssert_True(result, "OS_FileSys_FindVirtMountPoint(%s) (nominal) == true", refstr); /* Passing case with reference ending in "/" */ strncpy(OS_filesys_table[1].virtual_mountpt, "/ut", sizeof(OS_filesys_table[1].virtual_mountpt)); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(OS_filesys_table[1].virtual_mountpt)); result = OS_FileSys_FindVirtMountPoint((void *)refstr1, &token, &refobj); UtAssert_True(result, "OS_FileSys_FindVirtMountPoint(%s) (nominal) == true", refstr); } diff --git a/src/unit-test-coverage/shared/src/coveragetest-idmap.c b/src/unit-test-coverage/shared/src/coveragetest-idmap.c index 100108a7d..1b8f8ea8a 100644 --- a/src/unit-test-coverage/shared/src/coveragetest-idmap.c +++ b/src/unit-test-coverage/shared/src/coveragetest-idmap.c @@ -1087,7 +1087,6 @@ void Test_OS_GetResourceName(void) OSAPI_TEST_FUNCTION_RC(OS_GetResourceName(token.obj_id, NameBuffer, sizeof(NameBuffer)), OS_SUCCESS); UtAssert_True(strcmp(NameBuffer, "UTTask") == 0, "NameBuffer (%s) == UTTask", NameBuffer); - UT_SetDefaultReturnValue(UT_KEY(OS_strnlen), strlen(rptr->name_entry)); OSAPI_TEST_FUNCTION_RC(OS_GetResourceName(token.obj_id, NameBuffer, OSAL_SIZE_C(2)), OS_ERR_NAME_TOO_LONG); /* Null entry */ diff --git a/src/ut-stubs/CMakeLists.txt b/src/ut-stubs/CMakeLists.txt index 0e08cff30..1b3908d35 100644 --- a/src/ut-stubs/CMakeLists.txt +++ b/src/ut-stubs/CMakeLists.txt @@ -60,6 +60,7 @@ add_library(ut_osapi_stubs STATIC osapi-clock-stubs.c osapi-clock-handlers.c osapi-common-stubs.c + osapi-common-handlers.c osapi-condvar-stubs.c osapi-countsem-stubs.c osapi-countsem-handlers.c diff --git a/src/ut-stubs/osapi-common-handlers.c b/src/ut-stubs/osapi-common-handlers.c new file mode 100644 index 000000000..0cc8371aa --- /dev/null +++ b/src/ut-stubs/osapi-common-handlers.c @@ -0,0 +1,72 @@ +/************************************************************************ + * NASA Docket No. GSC-18,719-1, and identified as “core Flight System: Bootes” + * + * Copyright (c) 2020 United States Government as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ************************************************************************/ + +/** + * \file + * + * + * Stub implementations for the functions defined in the OSAL API + * + * The stub implementation can be used for unit testing applications built + * on top of OSAL. The stubs do not do any real function, but allow + * the return code to be crafted such that error paths in the application + * can be executed. + */ + +#include "osapi-common.h" /* OSAL public API for this subsystem */ +#include "utstub-helpers.h" + +/* + * ----------------------------------------------------------------- + * Default handler implementation for 'OS_strnlen' stub + * ----------------------------------------------------------------- + */ +void UT_DefaultHandler_OS_strnlen(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + const char *s; + const char *end; + size_t maxlen; + size_t retval; + int32 status; + + if (UT_Stub_GetInt32StatusCode(Context, &status)) + { + /* If a retval was supplied in the test case, then use it */ + retval = status; + } + else + { + s = UT_Hook_GetArgValueByName(Context, "s", const char *); + maxlen = UT_Hook_GetArgValueByName(Context, "maxlen", size_t); + + /* This is basically the real impl of strnlen, as it + * usually needs to give back the appropriate value in + * order to follow the expected path */ + end = memchr(s, 0, maxlen); + if (end == NULL) + { + retval = maxlen; + } + else + { + retval = end - s; + } + } + + UT_Stub_SetReturnValue(FuncKey, retval); +} diff --git a/src/ut-stubs/osapi-common-stubs.c b/src/ut-stubs/osapi-common-stubs.c index acb87a579..6ca8c0699 100644 --- a/src/ut-stubs/osapi-common-stubs.c +++ b/src/ut-stubs/osapi-common-stubs.c @@ -25,6 +25,8 @@ #include "osapi-common.h" #include "utgenstub.h" +void UT_DefaultHandler_OS_strnlen(void *, UT_EntryKey_t, const UT_StubContext_t *); + /* * ---------------------------------------------------- * Generated stub function for OS_API_Init() @@ -124,7 +126,7 @@ size_t OS_strnlen(const char *s, size_t maxlen) UT_GenStub_AddParam(OS_strnlen, const char *, s); UT_GenStub_AddParam(OS_strnlen, size_t, maxlen); - UT_GenStub_Execute(OS_strnlen, Basic, NULL); + UT_GenStub_Execute(OS_strnlen, Basic, UT_DefaultHandler_OS_strnlen); return UT_GenStub_GetReturnValue(OS_strnlen, size_t); } From 41738c4e0b912e890195c4d895933aad5f245838 Mon Sep 17 00:00:00 2001 From: Dylan Date: Tue, 2 Jul 2024 08:37:19 -0400 Subject: [PATCH 4/5] Updating documentation and version numbers for equuleus-rc1+dev73 --- CHANGELOG.md | 5 +++++ src/os/inc/osapi-version.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 213a8c974..fc3bf054e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## Development Build: equuleus-rc1+dev73 +- High-res timed stream ops +- Moves OS_strnlen to public API and adds static analysis comments +- See and + ## Development Build: equuleus-rc1+dev66 - Adds node20 compatible github actions - See diff --git a/src/os/inc/osapi-version.h b/src/os/inc/osapi-version.h index 31178cbba..2987b3a26 100644 --- a/src/os/inc/osapi-version.h +++ b/src/os/inc/osapi-version.h @@ -34,7 +34,7 @@ /* * Development Build Macro Definitions */ -#define OS_BUILD_NUMBER 66 +#define OS_BUILD_NUMBER 73 #define OS_BUILD_BASELINE "equuleus-rc1" #define OS_BUILD_DEV_CYCLE "equuleus-rc2" /**< @brief Development: Release name for current development cycle */ #define OS_BUILD_CODENAME "Equuleus" /**< @brief: Development: Code name for the current build */ From 5cc03556a61b2c9564eae386571272ea3fa4a4a7 Mon Sep 17 00:00:00 2001 From: dzbaker Date: Tue, 2 Jul 2024 12:30:42 -0400 Subject: [PATCH 5/5] Correcting status check in network-api-test.c that was referencing the incorrect status variable. --- src/tests/network-api-test/network-api-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/network-api-test/network-api-test.c b/src/tests/network-api-test/network-api-test.c index e206feb2d..7a4e231be 100644 --- a/src/tests/network-api-test/network-api-test.c +++ b/src/tests/network-api-test/network-api-test.c @@ -379,7 +379,7 @@ void Server_Fn(void) if (ServerFn_AcceptStatus != OS_SUCCESS) { snprintf(ServerFn_ErrorString, sizeof(ServerFn_ErrorString), "OS_SocketAccept() iter=%u, return code=%d", - (unsigned int)iter, (int)Status); + (unsigned int)iter, (int)ServerFn_AcceptStatus); break; }