diff options
Diffstat (limited to 'include/asterisk')
-rw-r--r-- | include/asterisk/ari.h | 11 | ||||
-rw-r--r-- | include/asterisk/autoconfig.h.in | 21 | ||||
-rw-r--r-- | include/asterisk/compiler.h | 6 | ||||
-rw-r--r-- | include/asterisk/http_websocket.h | 18 | ||||
-rw-r--r-- | include/asterisk/optional_api.h | 293 |
5 files changed, 188 insertions, 161 deletions
diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h index 4f2954000..dfeef513c 100644 --- a/include/asterisk/ari.h +++ b/include/asterisk/ari.h @@ -21,7 +21,7 @@ /*! \file * - * \brief Stasis RESTful API hooks. + * \brief Asterisk RESTful API hooks. * * This header file is used mostly as glue code between generated declarations * and res_ari.c. @@ -31,7 +31,14 @@ #include "asterisk/http.h" #include "asterisk/json.h" -#include "asterisk/http_websocket.h" + +/* Forward-declare websocket structs. This avoids including http_websocket.h, + * which causes optional_api stuff to happen, which makes optional_api more + * difficult to debug. */ + +struct ast_websocket_server; + +struct ast_websocket; /*! * \brief Configured encoding format for JSON output. diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 1796a3f68..87a769ed0 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -82,12 +82,21 @@ /* Define to 1 if your GCC C compiler supports the 'const' attribute. */ #undef HAVE_ATTRIBUTE_const +/* Define to 1 if your GCC C compiler supports the 'constructor' attribute. */ +#undef HAVE_ATTRIBUTE_constructor + /* Define to 1 if your GCC C compiler supports the 'deprecated' attribute. */ #undef HAVE_ATTRIBUTE_deprecated +/* Define to 1 if your GCC C compiler supports the 'destructor' attribute. */ +#undef HAVE_ATTRIBUTE_destructor + /* Define to 1 if your GCC C compiler supports the 'malloc' attribute. */ #undef HAVE_ATTRIBUTE_malloc +/* Define to 1 if your GCC C compiler supports the 'may_alias' attribute. */ +#undef HAVE_ATTRIBUTE_may_alias + /* Define to 1 if your GCC C compiler supports the 'pure' attribute. */ #undef HAVE_ATTRIBUTE_pure @@ -101,15 +110,6 @@ attribute. */ #undef HAVE_ATTRIBUTE_warn_unused_result -/* Define to 1 if your GCC C compiler supports the 'weak' attribute. */ -#undef HAVE_ATTRIBUTE_weak - -/* Define to 1 if your GCC C compiler supports the 'weak_import' attribute. */ -#undef HAVE_ATTRIBUTE_weak_import - -/* Define to 1 if your GCC C compiler supports the 'weakref' attribute. */ -#undef HAVE_ATTRIBUTE_weakref - /* Define to 1 if you have the Debug symbol decoding library. */ #undef HAVE_BFD @@ -720,6 +720,9 @@ /* Define to 1 if you have the `roundl' function. */ #undef HAVE_ROUNDL +/* Define if your system has the RTLD_NOLOAD headers. */ +#undef HAVE_RTLD_NOLOAD + /* Define to 1 if your system has /sbin/launchd. */ #undef HAVE_SBIN_LAUNCHD diff --git a/include/asterisk/compiler.h b/include/asterisk/compiler.h index 91112dbfe..77b5de40e 100644 --- a/include/asterisk/compiler.h +++ b/include/asterisk/compiler.h @@ -71,6 +71,12 @@ #define attribute_warn_unused_result #endif +#ifdef HAVE_ATTRIBUTE_may_alias +#define attribute_may_alias __attribute__((may_alias)) +#else +#define attribute_may_alias +#endif + /* Some older version of GNU gcc (3.3.5 on OpenBSD 4.3 for example) dont like 'NULL' as sentinel */ #define SENTINEL ((char *)NULL) diff --git a/include/asterisk/http_websocket.h b/include/asterisk/http_websocket.h index 82c7ad8b6..10cb9a023 100644 --- a/include/asterisk/http_websocket.h +++ b/include/asterisk/http_websocket.h @@ -22,6 +22,8 @@ #include "asterisk/http.h" #include "asterisk/optional_api.h" +#include <errno.h> + /*! * \file http_websocket.h * \brief Support for WebSocket connections within the Asterisk HTTP server. @@ -71,7 +73,7 @@ typedef void (*ast_websocket_callback)(struct ast_websocket *session, struct ast * \retval \c NULL on error * \since 12 */ -struct ast_websocket_server *ast_websocket_server_create(void); +AST_OPTIONAL_API(struct ast_websocket_server *, ast_websocket_server_create, (void), { return NULL; }); /*! * \brief Callback suitable for use with a \ref ast_http_uri. @@ -79,7 +81,7 @@ struct ast_websocket_server *ast_websocket_server_create(void); * Set the data field of the ast_http_uri to \ref ast_websocket_server. * \since 12 */ -int ast_websocket_uri_cb(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers); +AST_OPTIONAL_API(int, ast_websocket_uri_cb, (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers), { return -1; }); /*! * \brief Add a sub-protocol handler to the default /ws server @@ -141,7 +143,7 @@ AST_OPTIONAL_API(int, ast_websocket_server_remove_protocol, (struct ast_websocke * * \note Once an AST_WEBSOCKET_OPCODE_CLOSE opcode is received the socket will be closed */ -AST_OPTIONAL_API(int, ast_websocket_read, (struct ast_websocket *session, char **payload, uint64_t *payload_len, enum ast_websocket_opcode *opcode, int *fragmented), {return -1;}); +AST_OPTIONAL_API(int, ast_websocket_read, (struct ast_websocket *session, char **payload, uint64_t *payload_len, enum ast_websocket_opcode *opcode, int *fragmented), { errno = ENOSYS; return -1;}); /*! * \brief Construct and transmit a WebSocket frame @@ -154,7 +156,7 @@ AST_OPTIONAL_API(int, ast_websocket_read, (struct ast_websocket *session, char * * \retval 0 if successfully written * \retval -1 if error occurred */ -AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length), {return -1;}); +AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length), { errno = ENOSYS; return -1;}); /*! * \brief Close a WebSocket session by sending a message with the CLOSE opcode and an optional code @@ -165,7 +167,7 @@ AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum * \retval 0 if successfully written * \retval -1 if error occurred */ -AST_OPTIONAL_API(int, ast_websocket_close, (struct ast_websocket *session, uint16_t reason), {return -1;}); +AST_OPTIONAL_API(int, ast_websocket_close, (struct ast_websocket *session, uint16_t reason), { errno = ENOSYS; return -1;}); /*! * \brief Enable multi-frame reconstruction up to a certain number of bytes @@ -207,7 +209,7 @@ AST_OPTIONAL_API(void, ast_websocket_unref, (struct ast_websocket *session), {re * * \note You must *not* directly read from or write to this file descriptor. It should only be used for polling. */ -AST_OPTIONAL_API(int, ast_websocket_fd, (struct ast_websocket *session), {return -1;}); +AST_OPTIONAL_API(int, ast_websocket_fd, (struct ast_websocket *session), { errno = ENOSYS; return -1;}); /*! * \brief Get the remote address for a WebSocket connected session. @@ -222,7 +224,7 @@ AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_remote_address, (struct as * \retval 0 if unsecure * \retval 1 if secure */ -AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session), {return -1;}); +AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session), { errno = ENOSYS; return -1;}); /*! * \brief Set the socket of a WebSocket session to be non-blocking. @@ -230,6 +232,6 @@ AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session), * \retval 0 on success * \retval -1 on failure */ -AST_OPTIONAL_API(int, ast_websocket_set_nonblock, (struct ast_websocket *session), {return -1;}); +AST_OPTIONAL_API(int, ast_websocket_set_nonblock, (struct ast_websocket *session), { errno = ENOSYS; return -1;}); #endif diff --git a/include/asterisk/optional_api.h b/include/asterisk/optional_api.h index cc31ce0a6..7d66d2e47 100644 --- a/include/asterisk/optional_api.h +++ b/include/asterisk/optional_api.h @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2008, Digium, Inc. + * Copyright (C) 2008-2013, Digium, Inc. * * Kevin P. Fleming <kpfleming@digium.com> * @@ -30,19 +30,6 @@ * have only a part of their functionality dependent on the APIs, and can * provide the remainder even if the APIs are not available. * - * To accomodate this situation, the AST_OPTIONAL_API macro allows an API - * function to be declared in a special way, if Asterisk being built on a - * platform that supports special compiler and dynamic linker attributes. - * If so the API function will actually be a weak symbol, which means if the - * provider of the API is not loaded, the symbol can still be referenced (unlike a - * strong symbol, which would cause an immediate fault if not defined when - * referenced), but it will return NULL signifying the linker/loader was - * not able to resolve the symbol. In addition, the macro defines a hidden - * 'stub' version of the API call, using a provided function body, and uses - * various methods to make the API function symbol actually resolve to - * that hidden stub, but only when the *real* provider of the symbol has - * not been found. - * * An example can be found in agi.h: * * \code @@ -74,19 +61,6 @@ * apply special aliases to the function prototype; this can be done * by defining AST_API_MODULE just before including the header file * containing the AST_OPTIONAL_API macro calls. - * - * \note If the platform does not provide adequate resources, - * then the AST_OPTIONAL_API macro will result in a non-optional function - * definition; this means that any consumers of the API functions so - * defined will require that the provider of the API functions be - * loaded before they can reference the symbols. - * - * WARNING WARNING WARNING WARNING WARNING - * - * You MUST add the AST_MODFLAG_GLOBAL_SYMBOLS to the module for which you - * are enabling optional_api functionality, or it will fail to work. - * - * WARNING WARNING WARNING WARNING WARNING */ /*! @@ -99,150 +73,185 @@ */ #define AST_OPTIONAL_API_UNAVAILABLE INT_MIN - -#if defined(HAVE_ATTRIBUTE_weak_import) || defined(HAVE_ATTRIBUTE_weak) - -/* - * This is the Darwin (Mac OS/X) implementation, that only provides the 'weak' - * or 'weak_import' compiler attribute for weak symbols. On this platform, - * - * - The module providing the API will only provide a '__' prefixed version - * of the API function to other modules (this will be hidden from the other - * modules by the macros), so any modules compiled against older versions - * of the module that provided a non-prefixed version of the API function - * will fail to link at runtime. - * - In the API module itself, access to the API function without using a - * prefixed name is provided by a static pointer variable that holds the - * function address. - * - 'Consumer' modules of the API will use a combination of a weak_import or - * weak symbol, a local stub function, a pointer variable and a constructor - * function (which initializes that pointer variable as the module is being - * loaded) to provide safe, optional access to the API function without any - * special code being required. +/*! + * \def AST_OPTIONAL_API_NAME(name) + * \brief Expands to the name of the implementation function. */ -#if defined(HAVE_ATTRIBUTE_weak_import) -#define __default_attribute weak_import /* pre-Lion */ -#else -#define __default_attribute weak /* Lion-onwards */ -#endif - -#define AST_OPTIONAL_API_NAME(name) __##name - -#if defined(AST_API_MODULE) +/*! + * \def AST_OPTIONAL_API(result, name, proto, stub) + * \brief Declare an optional API function + * + * \param result The type of result the function returns + * \param name The name of the function + * \param proto The prototype (arguments) of the function + * \param stub The code block that will be used by the hidden stub when needed + * + * Example usage: + * \code + * AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd), + * { return AST_OPTIONAL_API_UNAVAILABLE; }); + * \endcode + */ -#define AST_OPTIONAL_API(result, name, proto, stub) \ - result AST_OPTIONAL_API_NAME(name) proto; \ - static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const name = AST_OPTIONAL_API_NAME(name); +/*! + * \def AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) + * \brief Declare an optional API function with compiler attributes + * + * \param result The type of result the function returns + * \param attr Any compiler attributes to be applied to the function (without the __attribute__ wrapper) + * \param name The name of the function + * \param proto The prototype (arguments) of the function + * \param stub The code block that will be used by the hidden stub when needed + */ -#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ - result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \ - static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const name = AST_OPTIONAL_API_NAME(name); +#if defined(OPTIONAL_API) -#else +#if !defined(HAVE_ATTRIBUTE_constructor) || !defined(HAVE_ATTRIBUTE_constructor) +#error OPTIONAL_API requires compiler constructor/destructor support +#endif -#define AST_OPTIONAL_API(result, name, proto, stub) \ - static result __stub__##name proto stub; \ - __attribute__((__default_attribute)) typeof(__stub__##name) AST_OPTIONAL_API_NAME(name); \ - static attribute_unused typeof(__stub__##name) * name; \ - static void __attribute__((constructor)) __init__##name(void) { name = AST_OPTIONAL_API_NAME(name) ? : __stub__##name; } +/*! + * \internal + * \brief Function pointer to an optional API function. + * + * Functions that are declared as optional may have any signature they want; + * they are cast to this type as needed. We don't use a \c void pointer, because + * technically data and function pointers are incompatible. + * + * \note + * The may_alias attribute is to avoid type punning/strict aliasing warnings + * with older GCC's. + */ +typedef void (*ast_optional_fn)(void) attribute_may_alias; -#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ - static __attribute__((attr)) result __stub__##name proto stub; \ - __attribute__((attr, __default_attribute)) typeof(__stub__##name) AST_OPTIONAL_API_NAME(name); \ - static attribute_unused __attribute__((attr)) typeof(__stub__##name) * name; \ - static void __attribute__((constructor)) __init__##name(void) { name = AST_OPTIONAL_API_NAME(name) ? : __stub__##name; } +/*! + * \internal + * \brief Provide an implementation of an optional API. + * + * Any declared usages of this function are linked. + * + * \param symname Name of the provided function. + * \param impl Function pointer to the implementation function. + */ +void ast_optional_api_provide(const char *symname, ast_optional_fn impl); -#endif +/*! + * \internal + * \brief Remove an implementation of an optional API. + * + * Any declared usages of this function are unlinked. + * + * \param symname Name of the provided function. + * \param impl Function pointer to the implementation function. + */ +void ast_optional_api_unprovide(const char *symname, ast_optional_fn impl); -/* End of Darwin (Mac OS/X) implementation */ +/*! + * \internal + * \brief Define a usage of an optional API. + * + * If the API has been provided, it will be linked into \a optional_ref. + * Otherwise, it will be linked to \a stub until an implementation is provided. + * + * \param symname Name of the function to use. + * \param optional_ref Pointer-to-function-pointer to link to impl/stub. + * \param stub Stub function to link to when impl is not available. + * \param module Name of the module requesting the API. + */ +void ast_optional_api_use(const char *symname, ast_optional_fn *optional_ref, + ast_optional_fn stub, const char *module); -#elif defined(HAVE_ATTRIBUTE_weakref) +/*! + * \internal + * \brief Remove a usage of an optional API. + * + * The \a optional_ref will be linked to the \a stub provided at use time, + * will no longer be updated if the API is provided/removed. + * + * \param symname Name of the function to use. + * \param optional_ref Pointer-to-function-pointer to link to impl/stub. + * \param module Name of the module requesting the API. + */ +void ast_optional_api_unuse(const char *symname, ast_optional_fn *optional_ref, + const char *module); -/* - * This is the generic GCC implementation, used when the 'weakref' - * compiler attribute is available. On these platforms: - * - * - The module providing the API will provide a '__' prefixed version - * of the API function to other modules (this will be hidden from the other - * modules by the macros), and also a non-prefixed alias so that modules - * compiled against older versions of the module that provided a non-prefixed - * version of the API function will continue to link properly. - * - In the API module itself, access to the API function without using a - * prefixed name is provided by the non-prefixed alias described above. - * - 'Consumer' modules of the API will use a combination of a weakref - * symbol, a local stub function, a pointer variable and a constructor function - * (which initializes that pointer variable as the module is being loaded) - * to provide safe, optional access to the API function without any special - * code being required. +/*! + * \brief Call at exit to clean up optional_api internals. + * + * Since the optional_api code might run before main() starts, it can't safely + * register its own cleanup handlers. That has to be done within main(). */ +void optional_api_cleanup(void); #define AST_OPTIONAL_API_NAME(name) __##name #if defined(AST_API_MODULE) - -#define AST_OPTIONAL_API(result, name, proto, stub) \ - result AST_OPTIONAL_API_NAME(name) proto; \ - static __attribute__((alias(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(AST_OPTIONAL_API_NAME(name)) name; - -#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ - result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \ - static __attribute__((alias(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(AST_OPTIONAL_API_NAME(name)) name; +/* Module defining the API */ + +#define AST_OPTIONAL_API_IMPL_INIT(name) \ + static void __attribute__((constructor)) __init__##name##_impl(void) { \ + ast_optional_api_provide(#name, \ + (ast_optional_fn)AST_OPTIONAL_API_NAME(name)); \ + } \ + static void __attribute__((destructor)) __dtor__##name##_impl(void) { \ + ast_optional_api_unprovide(#name, \ + (ast_optional_fn)AST_OPTIONAL_API_NAME(name)); \ + } + +#define AST_OPTIONAL_API(result, name, proto, stub) \ + result AST_OPTIONAL_API_NAME(name) proto; \ + static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const \ + name = AST_OPTIONAL_API_NAME(name); \ + AST_OPTIONAL_API_IMPL_INIT(name) + +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ + result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \ + static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const \ + name = AST_OPTIONAL_API_NAME(name); \ + AST_OPTIONAL_API_IMPL_INIT(name) #else +/* Module using the API */ -#define AST_OPTIONAL_API(result, name, proto, stub) \ - static result __stub__##name proto stub; \ - static __attribute__((weakref(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(__stub__##name) __ref__##name; \ - static attribute_unused typeof(__stub__##name) * name; \ - static void __attribute__((constructor)) __init__##name(void) { name = __ref__##name ? : __stub__##name; } +#define AST_OPTIONAL_API_INIT(name) \ + static void __attribute__((constructor)) __init__##name(void) { \ + ast_optional_api_use(#name, (ast_optional_fn *)&name, \ + (ast_optional_fn)__stub__##name, \ + AST_MODULE); \ + } \ + static void __attribute__((destructor)) __dtor__##name(void) { \ + ast_optional_api_unuse(#name, (ast_optional_fn *)&name, \ + AST_MODULE); \ + } -#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ - static __attribute__((attr)) result __stub__##name proto stub; \ - static __attribute__((attr, weakref(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(__stub__##name) __ref__##name; \ - static attribute_unused __attribute__((attr)) typeof(__stub__##name) * name; \ - static void __attribute__((constructor)) __init__##name(void) { name = __ref__##name ? : __stub__##name; } +#define AST_OPTIONAL_API(result, name, proto, stub) \ + static result __stub__##name proto stub; \ + static attribute_unused \ + typeof(__stub__##name) * name; \ + AST_OPTIONAL_API_INIT(name) -#endif +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ + static __attribute__((attr)) result __stub__##name proto stub; \ + static attribute_unused __attribute__((attr)) \ + typeof(__stub__##name) * name; \ + AST_OPTIONAL_API_INIT(name) -/* End of GCC implementation */ +#endif /* defined(AST_API_MODULE) */ -#else +#else /* defined(OPTIONAL_API) */ -/* This is the non-optional implementation. */ +/* Non-optional API */ #define AST_OPTIONAL_API_NAME(name) name -/*! - * \brief Define an optional API function - * - * \param result The type of result the function returns - * \param name The name of the function - * \param proto The prototype (arguments) of the function - * \param stub The code block that will be used by the hidden stub when needed - * - * Example usage: - * \code - * AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd), - * { return AST_OPTIONAL_API_UNAVAILABLE; }); - * \endcode - */ -#define AST_OPTIONAL_API(result, name, proto, stub) result AST_OPTIONAL_API_NAME(name) proto +#define AST_OPTIONAL_API(result, name, proto, stub) \ + result AST_OPTIONAL_API_NAME(name) proto -/*! - * \brief Define an optional API function with compiler attributes - * - * \param result The type of result the function returns - * \param attr Any compiler attributes to be applied to the function (without the __attribute__ wrapper) - * \param name The name of the function - * \param proto The prototype (arguments) of the function - * \param stub The code block that will be used by the hidden stub when needed - */ -#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto - -/* End of non-optional implementation */ +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ + result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto -#endif +#endif /* defined(OPTIONAL_API) */ #undef AST_API_MODULE |