diff --git a/modules/libcom/src/cxxTemplates/epicsGuard.h b/modules/libcom/src/cxxTemplates/epicsGuard.h index fc68d8757..89b67f2d8 100644 --- a/modules/libcom/src/cxxTemplates/epicsGuard.h +++ b/modules/libcom/src/cxxTemplates/epicsGuard.h @@ -8,6 +8,14 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ +/*! + * \file epicsGuard.h + * \brief Provides classes for RAII style locking and unlocking of mutexes + * + * Provides classes for RAII style locking and unlocking of mutexes + * + **/ + #ifndef epicsGuardh #define epicsGuardh @@ -21,14 +29,39 @@ template < class T > class epicsGuardRelease; -// Automatically applies and releases the mutex. -// This class is also useful in situations where -// C++ exceptions are possible. +/*! + * \brief Provides an RAII style lock/unlock of a mutex. + * + * Provides an RAII style lock/unlock of a mutex. When this object is created, + * it attempts to lock the mutex it was given. When control leaves the scope + * where this was created, the destructor unlocks the mutex. + * + * This class is also useful in situations where C++ exceptions are possible. + * + * Example + * ======= + * \code{.cpp} + * epicsMutex mutex; + * { + * epicsGuard guard(mutex); + * printf("mutex is locked") + * } + * printf("mutex is unlocked\n"); + * \endcode + **/ template < class T > class epicsGuard { public: typedef epicsGuardRelease release_t; - epicsGuard ( T & ); + + /*! + * \brief Guard a mutex based on scope. + * + * Constructs an epicsGuard, locking the mutex for the scope of this object. + * + * \param mutexIn A mutex-like object to be lock()'ed and unlock()'ed + */ + epicsGuard ( T & mutexIn); void assertIdenticalMutex ( const T & ) const; ~epicsGuard (); private: @@ -38,14 +71,45 @@ private: friend class epicsGuardRelease < T >; }; -// Automatically releases and reapplies the mutex. -// This class is also useful in situations where -// C++ exceptions are possible. + +/*! + * \brief RAII style unlocking of an epicsGuard object + * + * RAII style unlocking of an epicsGuard object This class can be used while a + * epicsGuard is active to temporarily release the mutex and automatically + * re-apply the lock when this object goes out of scope. + * + * This class is also useful in situations where C++ exceptions are possible. + * + * Example + * ======= + * \code{.cpp} + * epicsMutex mutex; + * { + * epicsGuard guard(mutex); + * printf("mutex is locked"); + * { + * epicsGuardRelease grelease(guard); + * printf("mutex is unlocked"); + * } + * printf("mutex is locked"); + * } + * printf("mutex is unlocked"); + * \endcode + * + */ template < class T > class epicsGuardRelease { public: typedef epicsGuard guard_t; - epicsGuardRelease ( epicsGuard < T > & ); + /*! + * \brief Constructs an epicsGuardRelease, unlocking the given epicsGuard + * + * Constructs an epicsGuardRelease, unlocking the given epicsGuard for the duration of this object. + * + * \param guardIn The epicsGuard object to be temporarily released. + */ + epicsGuardRelease ( epicsGuard < T > & guardIn); ~epicsGuardRelease (); private: epicsGuard < T > & _guard; @@ -55,11 +119,20 @@ private: }; // same interface as epicsMutex +/*! + * \brief Mutex-like object that does nothing. + * + * This object can be passed into an epicsGuard or similar interface when no actual locking is needed. + */ class epicsMutexNOOP { public: + //! Does nothing void lock (); + //! Does nothing, always returns true. bool tryLock (); + //! Does nothing void unlock (); + //! Does nothing void show ( unsigned level ) const; }; diff --git a/modules/libcom/src/misc/testMain.h b/modules/libcom/src/misc/testMain.h index f4512bcbe..dfaa4cadb 100644 --- a/modules/libcom/src/misc/testMain.h +++ b/modules/libcom/src/misc/testMain.h @@ -9,15 +9,20 @@ #ifndef INC_testMain_H #define INC_testMain_H -/* This header defines a convenience macro for use by pure test programs. +/*! + * \file testMain.h + * + * \brief This header defines a platform independent macro for defining a test + * main function, in pure test programs. + * * A pure test program cannot take any arguments since it must be fully * automatable. If your program needs to use argv/argc, it may be doing * measurements not unit and/or regression testing. On Host architectures * these programs needs to be named main and take dummy argc/argv args, * but on vxWorks and RTEMS they must be named as the test program. * - * Use this macro as follows: - * + * \section Example + * \code{.cpp} * #include "testMain.h" * #include "epicsUnitTest.h" * @@ -26,8 +31,14 @@ * testOk(...) * return testDone(); * } + * \endcode */ +/*! + * \def MAIN + * \brief Macro which defines a main function for your test program. Some platforms will name this function main(), others prog(). + * \param prog Name of the test program. + **/ #if defined(__rtems__) #ifdef __cplusplus #define MAIN(prog) extern "C" int prog(void); extern "C" int main() __attribute__((weak, alias(#prog))); extern "C" int prog(void) diff --git a/modules/libcom/src/osi/epicsMessageQueue.h b/modules/libcom/src/osi/epicsMessageQueue.h index 4a2925600..c477b74ff 100644 --- a/modules/libcom/src/osi/epicsMessageQueue.h +++ b/modules/libcom/src/osi/epicsMessageQueue.h @@ -84,8 +84,8 @@ public: /** * \brief Send a message or timeout. - * \param message Pointer to the data to be sent. - * \param messageSize How many bytes to send. + * \param message Pointer to the message to be sent + * \param messageSize The size of \p message * \param timeout The timeout delay in seconds. A timeout of zero is * equivalent to calling trySend(); NaN or any value too large to be * represented to the target OS is equivalent to no timeout. @@ -99,6 +99,9 @@ public: /** * \brief Try to receive a message. + * \param[out] message Output buffer to store the received message + * \param size Size of the buffer pointed to by \p message + * * If the queue holds at least one message, * the first message on the queue is moved to the specified location * and the length of that message is returned. @@ -115,6 +118,9 @@ public: /** * \brief Fetch the next message on the queue. + * \param[out] message Output buffer to store the received message + * \param size Size of the buffer pointed to by \p message + * * Wait for a message to be sent if the queue is empty, then move * the first message queued to the specified location. * @@ -130,8 +136,8 @@ public: /** * \brief Wait for and fetch the next message. - * \param message Buffer to hold message. - * \param size Bytes available in the buffer. + * \param[out] message Output buffer to store the received message + * \param size Size of the buffer pointed to by \p message * \param timeout The timeout delay in seconds. A timeout of zero is * equivalent to calling tryReceive(); NaN or any value too large to * be represented to the target OS is equivalent to no timeout. diff --git a/modules/libcom/src/osi/osiSock.h b/modules/libcom/src/osi/osiSock.h index 98eb2c140..59332a04b 100644 --- a/modules/libcom/src/osi/osiSock.h +++ b/modules/libcom/src/osi/osiSock.h @@ -8,11 +8,17 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* - * socket support library API def +/*! + * \file osiSock.h + * \brief Platform independent socket support library API * - * 7-1-97 -joh- + * osiSock library contains platform independent APIs for creating sockets, + * converting between socket address structures and human readable strings, and + * configuring sockets. */ + +/* Author: joh 1997-07-01 */ + #ifndef osiSockh #define osiSockh @@ -28,185 +34,378 @@ struct sockaddr; struct sockaddr_in; struct in_addr; +/*! + * \brief Create a socket object + * + * Ask the operating system to create a socket and return its file descriptor. + * + * \param domain The socket domain, e.g. PF_INET + * \param type The type of socket, e.g. SOCK_STREAM (tcp) or SOCK_DGRAM (udp) + * \param protocol Typically unused and set to 0. + * \return A file descriptor referring to the socket, or -1 on error. + */ LIBCOM_API SOCKET epicsStdCall epicsSocketCreate ( int domain, int type, int protocol ); + +/*! + * \brief Accept a connection on a listening stream socket. + * + * epicsSocketAccept is used with connection-based sockets. It takes the next + * connection request in the queue and returns a new socket that can be used to + * communicate with the listener. + * + * \param sock socket with pending connections to accept + * \param pAddr If not NULL, this socket contains the address of the peer whose + * connection is being accepted + * \param[in,out] addrlen Caller must initialize this to the length of the + * structure pointed to by \p pAddr, or set to NULL if \p pAddr is NULL. This + * function will update the value of this parameter to the actual size of the + * peer address. + * \return A new socket used for communicating with the peer just accepted, or -1 on error. + */ LIBCOM_API int epicsStdCall epicsSocketAccept ( int sock, struct sockaddr * pAddr, osiSocklen_t * addrlen ); +/*! + * \brief Close and free resources held by a SOCKET object. + * + * Close and free resources held by a SOCKET object. + */ LIBCOM_API void epicsStdCall epicsSocketDestroy ( SOCKET ); +/*! + * \brief Allows a socket to bind ignoring other sockets in TIME_WAIT state. + * + * Allows a socket to bind while other sockets hold the same address and port + * but are in the TIME_WAIT state. TIME_WAIT is a state where a socket has + * closed locally, but is waiting to be closed on the remote end. If the remote + * end doesn't respond, this can block another socket from binding to that + * address:port for a long time (possibly minutes). This option allows the + * socket to bind to an address:port combo, even if there's another socket with + * the same address:port that's waiting for the remote side to close its + * connection. + * + * See also: Linux's SO_REUSEADDR in setsockopt. + * + * \param s The socket to ignore other TIME_WAIT sockets when binding + */ LIBCOM_API void epicsStdCall epicsSocketEnableAddressReuseDuringTimeWaitState ( SOCKET s ); +/*! + * \brief Allows multiple sockets to use the same family, local address, and local + * port + * + * Allows multiple sockets to use the same family, local address, and port. By + * having multiple sockets open with this setting enabled, the OS will + * distribute the datagrams (for UDP sockets) or connection requests (for + * TCP/stream sockets) among the sockets with this option set. Note that all + * sockets binding to the same address and port must have this option set. + * + * As an example, this option could be a way to implement a form of load + * balancing between multiple threads or processes with sockets bound to the + * same address:port. + * + * \param s The socket to put in "Fanout" mode (aka REUSEPORT mode) + */ LIBCOM_API void epicsStdCall epicsSocketEnableAddressUseForDatagramFanout ( SOCKET s ); -/* - * Fortunately, on most systems the combination of a shutdown of both - * directions and or a signal is sufficent to interrupt a blocking send, - * receive, or connect call. For odd ball systems this is stubbed out in the - * osi area. +/*! + * \brief Enum specifying how to interrupt a blocking socket system call + * + * This enum specifies how to interrupt a blocking socket system call. + * Fortunately, on most systems the combination of a shutdown of both directions + * and/or a signal is sufficent to interrupt a blocking send, receive, or + * connect call. For odd ball systems this is stubbed out in the osi area. + * */ enum epicsSocketSystemCallInterruptMechanismQueryInfo { + //! Calling close() required to interrupt esscimqi_socketCloseRequired, + + //! calling shutdown() for both read and write required to interrupt esscimqi_socketBothShutdownRequired, - esscimqi_socketSigAlarmRequired /* NO LONGER USED/SUPPORTED */ + + //! NO LONGER USED/SUPPORTED + esscimqi_socketSigAlarmRequired }; + +/*! + * \brief Query what approach to use to interrupt blocking socket calls + * + * This function tells you what approach to use to interrupt calls blocked on + * socket operations. + * + * \return enum representing whether to call close() or shutdown(RW) to + * interrupt blocking socket syscalls. + */ LIBCOM_API enum epicsSocketSystemCallInterruptMechanismQueryInfo epicsSocketSystemCallInterruptMechanismQuery (); #ifdef EPICS_PRIVATE_API -/* - * Some systems (e.g Linux and Windows 10) allow to check the amount - * of unsent data in the output queue. - * Returns -1 if the information is not available. +/*! + * \brief Query unsent data in a socket's output queue + * + * Query unsent data in a socket's output queue. Some systems (e.g Linux and + * Windows 10) allow to check the amount of unsent data in the output queue. + * + * \param sock Socket to query for unsent data + * \return The number of bytes of unsent data in the output queue. Returns -1 if the + * information is not available. */ LIBCOM_API int epicsSocketUnsentCount(SOCKET sock); #endif -/* - * convert socket address to ASCII in this order - * 1) look for matching host name and typically add trailing IP port - * 2) failing that, convert to raw ascii address (typically this is a - * dotted IP address with trailing port) - * 3) failing that, writes "" into pBuf +/*! + * \brief Convert socket address to ASCII * - * returns the number of character elements stored in buffer not + * Converts a socket address to an ASCII string. Conversion occurs in this + * order: + * 1. look for matching host name and typically add trailing IP port + * 2. failing that, convert to raw ascii address (typically this is a + * dotted IP address with trailing port) + * 3. failing that, writes "" into pBuf + * + * \param paddr sockaddr structure to convert to ascii address:port + * \param[out] pBuf Pointer to the output buffer contantaining the address:port string + * \param bufSize Length of pBuf array + * \return The number of character elements stored in buffer not * including the null termination, but always writes at least a * null terminator in the string (if bufSize >= 1) */ LIBCOM_API unsigned epicsStdCall sockAddrToA ( const struct sockaddr * paddr, char * pBuf, unsigned bufSize ); -/* - * convert IP address to ASCII in this order +/*! + * \brief Convert IP address to ASCII + * + * Convert an IP address to an ASCII string. Conversion occurs in this order: * 1) look for matching host name and add trailing port * 2) convert to raw dotted IP address with trailing port * - * returns the number of character elements stored in buffer not - * including the null termination, but always writes at least a - * null terminator in the string (if bufSize >= 1) + * \param pInetAddr sockaddr_in structure to convert to address string + * \param[out] pBuf Pointer to the char array where the address string will be stored + * \param bufSize Length of the array to which pBuf points + * \return The number of character elements stored in buffer not including the + * null termination, but always writes at least a null terminator in the string + * (if bufSize >= 1) */ LIBCOM_API unsigned epicsStdCall ipAddrToA ( const struct sockaddr_in * pInetAddr, char * pBuf, unsigned bufSize ); -/* - * sockAddrToDottedIP () - * typically convert to raw dotted IP address with trailing port +/*! + * \brief Convert to raw dotted IP address with trailing port * - * returns the number of character elements stored in buffer not - * including the null termination, but always writes at least a - * null terminator in the string (if bufSize >= 1) + * Convert an address to a raw dotted IP address. Compared to sockAddrToA(), + * this call will always convert to a raw dotted IP (e.g. 192.168.0.1) and not + * use host names (e.g. localhost) when available + * + * \param paddr sockaddr structure containing the node and service info to convert to strings + * \param[out] pBuf Pointer to a character buffer where the output string will be placed. + * \param bufSize Size of the array pointed to by pBuf + * \return The number of character elements stored in buffer not including the + * null termination, but always writes at least a null terminator in the string + * (if bufSize >= 1) */ LIBCOM_API unsigned epicsStdCall sockAddrToDottedIP ( const struct sockaddr * paddr, char * pBuf, unsigned bufSize ); -/* - * ipAddrToDottedIP () - * convert to raw dotted IP address with trailing port +/*! + * \brief Convert to raw dotted IP address with trailing port * - * returns the number of character elements stored in buffer not - * including the null termination, but always writes at least a - * null terminator in the string (if bufSize >= 1) + * Convert a sockaddr_in to a raw dotted IP address string with trailing port. Similar + * to sockAddrToDottedIP but takes a sockaddr_in structure. + * + * \param paddr sockaddr_in structure containing the node and service info to convert to strings + * \param[out] pBuf Pointer to a character buffer where the output string will be placed + * \param bufSize Size of the array pointed to by pBuf + * \return The number of character elements stored in buffer not including the + * null termination, but always writes at least a null terminator in the string + * (if bufSize >= 1) */ LIBCOM_API unsigned epicsStdCall ipAddrToDottedIP ( const struct sockaddr_in * paddr, char * pBuf, unsigned bufSize ); -/* - * convert inet address to a host name string +/*! + * \brief Convert inet address to a host name string * - * returns the number of character elements stored in buffer not - * including the null termination. This will be zero if a matching - * host name cant be found. + * Convert an inet address to a host name string. There are many OS specific + * implementation stubs for this routine * - * there are many OS specific implementation stubs for this routine + * \param pAddr sockaddr_in structure containing the node and service info to convert to strings + * \param[out] pBuf Pointer to a character buffer where the output string will be placed + * \param bufSize Size of the array pointed to by pBuf + * \return the number of character elements stored in buffer not including the + * null termination. This will be zero if a matching host name cant be found. */ LIBCOM_API unsigned epicsStdCall ipAddrToHostName ( const struct in_addr * pAddr, char * pBuf, unsigned bufSize ); -/* - * attempt to convert ASCII string to an IP address in this order - * 1) look for traditional doted ip with optional port - * 2) look for raw number form of ip address with optional port - * 3) look for valid host name with optional port +/*! + * \brief Attempt to convert ASCII string to an IP address + * + * Attempt to convert ASCII string to an IP address. Conversion occurs this + * order: + * 1. look for traditional doted ip with optional port + * 2. look for raw number form of ip address with optional port + * 3. look for valid host name with optional port + * + * \param pAddrString IP address string to convert to a sockaddr_in (e.g. "192.168.0.1:80") + * \param defaultPort The default port (service) to use if not specified in pAddrString + * \param[out] pIP Pointer to a sockaddr_in where the converted address info will be stored + * \return negative value on error, 0 on success. */ LIBCOM_API int epicsStdCall aToIPAddr ( const char * pAddrString, unsigned short defaultPort, struct sockaddr_in * pIP); -/* - * attempt to convert ASCII host name string with optional port to an IP address +/*! + * \brief Attempt to convert ASCII host name string with optional port to an IP address + * + * Convert an in_addr struct to a human readable hostname. + * + * \param pHostName ASCII host name to convert + * \param[out] pIPA Pointer to the in_addr structure where the hostname information will be stored + * \return 0 on success, negative on error. */ LIBCOM_API int epicsStdCall hostToIPAddr (const char *pHostName, struct in_addr *pIPA); -/* - * attach to BSD socket library +/*! + * \brief attach to BSD socket library + + * Attach to the BSD socket library in preparation for using sockets. If the OS + * does not require attaching to the socket library, this function does nothing. + * + * \return true on success, false on error. */ LIBCOM_API int epicsStdCall osiSockAttach (void); /* returns T if success, else F */ -/* - * release BSD socket library +/*! + * \brief release BSD socket library + * + * Release the BSD socket library if the OS requires it. For platforms that do + * not require attaching and releasing to use the socket library, this function + * does nothing. */ LIBCOM_API void epicsStdCall osiSockRelease (void); -/* - * convert socket error numbers to a string +/*! + * \brief convert socket error numbers to a string + * + * There are several system functions which set errno on failure. This function + * converts that error number into a string describing the error. + * + * \param[out] pBuf Pointer to char array where the error string will be stored + * \param bufSize Length of the array pointed to by pBuf + * \param error The error number to describe in string form */ LIBCOM_API void epicsSocketConvertErrorToString ( char * pBuf, unsigned bufSize, int error ); + +/*! + * \brief Convert the currently set errno to a string + * + * errno is a global integer that gets set when certain functions return an + * error. This function converts that error value into a string describing the + * error. + * + * \param[out] pBuf Pointer to char array where the error string will be stored + * \param bufSize Length of the array pointed to by pBuf + */ LIBCOM_API void epicsSocketConvertErrnoToString ( char * pBuf, unsigned bufSize ); +/*! + * \brief Union to switch between sockaddr_in and sockaddr + * + * A union to switch between sockaddr_in and sockaddr. Several socket related + * calls require casting between a sockaddr and a sockaddr_in. This union makes + * that casting between the two more convenient. + */ typedef union osiSockAddr { struct sockaddr_in ia; struct sockaddr sa; } osiSockAddr; +/*! + * \brief Stores a list of socket addresses + * + * Container to store a list of socket addresses + */ typedef struct osiSockAddrNode { ELLNODE node; osiSockAddr addr; } osiSockAddrNode; -/* - * sockAddrAreIdentical() - * (returns true if addresses are identical) +/*! + * \brief Compares two osiSockAddrs + * + * Compares two osiSockAddrs + * + * \return true if addresses are identical, false otherwise. */ LIBCOM_API int epicsStdCall sockAddrAreIdentical ( const osiSockAddr * plhs, const osiSockAddr * prhs ); -/* - * osiSockDiscoverBroadcastAddresses () - * Returns the broadcast addresses of each network interface found. +/*! + * \brief Add available broadcast addresses to a list * - * This routine is provided with the address of an ELLLIST, a socket, - * a destination port number, and a match address. When the - * routine returns there will be one additional entry - * (an osiSockAddrNode) in the list for each network interface found that - * is up and isn't a loop back interface (match addr is INADDR_ANY), - * or only the interfaces that match the specified addresses (match addr - * is other than INADDR_ANY). If the interface supports broadcasting - * then add its broadcast address to the list. If the interface is a - * point to point link then add the destination address of the point to - * point link to the list. + * Add available broadcast addresses to a list. This routine is provided with + * the address of an ELLLIST, a socket, and a match address. When the routine + * returns there will be one additional entry in the list for each network + * interface found that is up and isn't a loop back interface (match addr is + * INADDR_ANY), or only the interfaces that match the specified addresses + * (match addr is other than INADDR_ANY). If the interface supports + * broadcasting then add its broadcast address to the list. If the interface is + * a point to point link then add the destination address of the point to point + * link to the list. * * Any mutex locking required to protect pList is applied externally. * + * Example + * ======= + * \code{.cpp} + * ELLLIST ifaces = ELLLIST_INIT; + * ELLNODE * cur; + * SOCKET dummy = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); + * osiSockAddr match; + * + * memset(&match, 0, sizeof(match)); + * match.ia.sin_family = AF_INET; + * match.ia.sin_addr.s_addr = htonl(INADDR_ANY); + * + * osiSockDiscoverBroadcastAddresses(&ifaces, dummy, &match); + * for (cur = ellFirst(&ifaces); cur; cur = ellNext(cur)) { + * char name[64]; + * osiSockAddrNode * n = CONTAINER(cur, osiSockAddrNode, node); + * node->addr.ia.sin_port = htons(5555); + * sockAddrToDottedIP(&node->addr.sa, name, sizeof(name); + * fprintf(stderr, "Node is %s", name); + * } + ellFree(&ifaces); + epicsSocketDestroy(dummy); + * \endcode + * + * \param[out] pList Pointer to a list where network interfaces will be added as new osiSockAddrNode's + * \param socket (May be unused) + * \param pMatchAddr Only add addresses that match this address. Use + * match.ia.sin_addr.s_addr = htonl(INADDR_ANY) to match any address. + * \return The broadcast addresses of each network interface found. */ LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses (ELLLIST *pList, SOCKET socket, const osiSockAddr *pMatchAddr); -/* - * osiLocalAddr () - * Returns the osiSockAddr of the first non-loopback interface found - * that is operational (up flag is set). If no valid address can be - * located then return an osiSockAddr with the address family set to - * unspecified (AF_UNSPEC). +/*! + * Returns the osiSockAddr of the first non-loopback interface found that is + * operational (up flag is set). If no valid address can be located then return + * an osiSockAddr with the address family set to unspecified (AF_UNSPEC). * - * Unfortunately in EPICS 3.13 beta 11 and before the CA - * repeater would not always allow the loopback address - * as a local client address so current clients alternate - * between the address of the first non-loopback interface - * found and the loopback address when subscribing with - * the CA repeater until all CA repeaters have been updated - * to current code. After all CA repeaters have been restarted - * this osi interface can be eliminated. + * Unfortunately in EPICS 3.13 beta 11 and before the CA repeater would not + * always allow the loopback address as a local client address so current + * clients alternate between the address of the first non-loopback interface + * found and the loopback address when subscribing with the CA repeater until + * all CA repeaters have been updated to current code. + * + * \note After all CA repeaters have been restarted this osi interface can be + * eliminated. */ LIBCOM_API osiSockAddr epicsStdCall osiLocalAddr (SOCKET socket);