Home | History | Annotate | Line # | Download | only in ServiceRegistration
      1  1.1  christos /* srp.h
      2  1.1  christos  *
      3  1.1  christos  * Copyright (c) 2018-2024 Apple Inc. All rights reserved.
      4  1.1  christos  *
      5  1.1  christos  * Licensed under the Apache License, Version 2.0 (the "License");
      6  1.1  christos  * you may not use this file except in compliance with the License.
      7  1.1  christos  * You may obtain a copy of the License at
      8  1.1  christos  *
      9  1.1  christos  *     https://www.apache.org/licenses/LICENSE-2.0
     10  1.1  christos  *
     11  1.1  christos  * Unless required by applicable law or agreed to in writing, software
     12  1.1  christos  * distributed under the License is distributed on an "AS IS" BASIS,
     13  1.1  christos  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  1.1  christos  * See the License for the specific language governing permissions and
     15  1.1  christos  * limitations under the License.
     16  1.1  christos  *
     17  1.1  christos  * Service Registration Protocol common definitions
     18  1.1  christos  */
     19  1.1  christos 
     20  1.1  christos #ifndef __SRP_H
     21  1.1  christos #define __SRP_H
     22  1.1  christos 
     23  1.1  christos #ifdef __cplusplus
     24  1.1  christos extern "C" {
     25  1.1  christos #endif
     26  1.1  christos 
     27  1.1  christos #ifndef THREAD_DEVKIT_ADK
     28  1.1  christos #include <netinet/in.h>
     29  1.1  christos #endif
     30  1.1  christos #include <stdint.h>
     31  1.1  christos #include <stdbool.h>
     32  1.1  christos #include <string.h>
     33  1.1  christos #ifdef POSIX_BUILD
     34  1.1  christos #include <limits.h>
     35  1.1  christos #include <sys/param.h>
     36  1.1  christos #endif
     37  1.1  christos #ifdef MALLOC_DEBUG_LOGGING
     38  1.1  christos #  define MDNS_NO_STRICT 1
     39  1.1  christos #endif
     40  1.1  christos 
     41  1.1  christos #include "srp-features.h"           // for feature flags
     42  1.1  christos 
     43  1.1  christos 
     44  1.1  christos #ifdef __clang__
     45  1.1  christos #define NULLABLE _Nullable
     46  1.1  christos #define NONNULL _Nonnull
     47  1.1  christos #define UNUSED __unused
     48  1.1  christos #else
     49  1.1  christos #define NULLABLE
     50  1.1  christos #define NONNULL
     51  1.1  christos #define UNUSED __attribute__((unused))
     52  1.1  christos #ifdef POSIX_BUILD
     53  1.1  christos #else
     54  1.1  christos #define SRP_CRYPTO_MBEDTLS 1
     55  1.1  christos #endif // POSIX_BUILD
     56  1.1  christos #endif
     57  1.1  christos 
     58  1.1  christos #define INT64_HEX_STRING_MAX 17     // Maximum size of an int64_t printed as hex, including NUL termination
     59  1.1  christos 
     60  1.1  christos #ifdef __clang__
     61  1.1  christos #pragma clang diagnostic push
     62  1.1  christos #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
     63  1.1  christos #endif
     64  1.1  christos //======================================================================================================================
     65  1.1  christos 
     66  1.1  christos #ifdef __clang__
     67  1.1  christos #pragma clang diagnostic pop
     68  1.1  christos #endif
     69  1.1  christos 
     70  1.1  christos #include "srp-log.h"                // For log functions
     71  1.1  christos 
     72  1.1  christos #define SRP_OBJ_REF_COUNT_LIMIT    10000
     73  1.1  christos 
     74  1.1  christos #ifdef __clang__
     75  1.1  christos #define FILE_TRIM(x) (strrchr(x, '/') + 1)
     76  1.1  christos #else
     77  1.1  christos #define FILE_TRIM(x) (x)
     78  1.1  christos #endif
     79  1.1  christos 
     80  1.1  christos #ifdef THREAD_DEVKIT_ADK
     81  1.1  christos #define FINALIZED(x)
     82  1.1  christos #define CREATED(x)
     83  1.1  christos #else
     84  1.1  christos #define FINALIZED(x) ((x)++)
     85  1.1  christos #define CREATED(x) ((x)++)
     86  1.1  christos #endif // THREAD_DEVKIT_ADK
     87  1.1  christos 
     88  1.1  christos #ifdef DEBUG_VERBOSE
     89  1.1  christos #ifdef __clang_analyzer__
     90  1.1  christos #define RELEASE_BASE(x, object_type, file, line) \
     91  1.1  christos     object_type ## _finalize(x)
     92  1.1  christos #else
     93  1.1  christos #define RELEASE_BASE(x, object_type, file, line) do {                             \
     94  1.1  christos         if ((x) != NULL) {                                                        \
     95  1.1  christos             if ((x)->ref_count == 0) {                                            \
     96  1.1  christos                 FAULT("ALLOC: release after finalize at %2.2d: %p (%10s): %s:%d", \
     97  1.1  christos                       (x)->ref_count, (void *)(x), # x, FILE_TRIM(file), line);   \
     98  1.1  christos                 abort();                                                          \
     99  1.1  christos             } else if ((x)->ref_count > SRP_OBJ_REF_COUNT_LIMIT) {                \
    100  1.1  christos                 FAULT("ALLOC: release at %2.2d: %p (%10s): %s:%d",                \
    101  1.1  christos                       (x)->ref_count, (void *)(x), # x, FILE_TRIM(file), line);   \
    102  1.1  christos                 abort();                                                          \
    103  1.1  christos             } else {                                                              \
    104  1.1  christos                 INFO("ALLOC: release at %2.2d: %p (%10s): %s:%d",                 \
    105  1.1  christos                      (x)->ref_count, (void *)(x), # x, FILE_TRIM(file), line);    \
    106  1.1  christos                 --(x)->ref_count;                                                 \
    107  1.1  christos                 if ((x)->ref_count == 0) {                                        \
    108  1.1  christos                     INFO("ALLOC:      finalize: %p (%10s): %s:%d",                \
    109  1.1  christos                          (void *)(x), # x, FILE_TRIM(file), line);                \
    110  1.1  christos                     FINALIZED(object_type##_finalized);                           \
    111  1.1  christos                     object_type##_finalize(x);                                    \
    112  1.1  christos                 }                                                                 \
    113  1.1  christos             }                                                                     \
    114  1.1  christos         }                                                                         \
    115  1.1  christos     } while (0)
    116  1.1  christos 
    117  1.1  christos #endif // __clang_analyzer__
    118  1.1  christos #define RETAIN_BASE(x, object_type, file, line) do {                              \
    119  1.1  christos         if ((x) != NULL) {                                                        \
    120  1.1  christos             INFO("ALLOC:  retain at %2.2d: %p (%10s): %s:%d",                     \
    121  1.1  christos                  (x)->ref_count, (void *)(x), # x, FILE_TRIM(file), line);        \
    122  1.1  christos             if ((x)->ref_count == 0) {                                            \
    123  1.1  christos                CREATED(object_type##_created);                                    \
    124  1.1  christos             }                                                                     \
    125  1.1  christos             ++((x)->ref_count);                                                   \
    126  1.1  christos             if ((x)->ref_count > SRP_OBJ_REF_COUNT_LIMIT) {                       \
    127  1.1  christos                 FAULT("ALLOC: retain at %2.2d: %p (%10s): %s:%d",                 \
    128  1.1  christos                       (x)->ref_count, (void *)(x), # x, FILE_TRIM(file), line);   \
    129  1.1  christos                 abort();                                                          \
    130  1.1  christos             }                                                                     \
    131  1.1  christos         }                                                                         \
    132  1.1  christos     } while (0)
    133  1.1  christos #define RELEASE(x, object_type) RELEASE_BASE(x, object_type, file, line)
    134  1.1  christos #define RETAIN(x, object_type) RETAIN_BASE(x, object_type, file, line)
    135  1.1  christos #define RELEASE_HERE(x, object_type) RELEASE_BASE(x, object_type, __FILE__, __LINE__)
    136  1.1  christos #define RETAIN_HERE(x, object_type) RETAIN_BASE(x, object_type, __FILE__, __LINE__)
    137  1.1  christos #else // DEBUG_VERBOSE
    138  1.1  christos #ifdef __clang_analyzer__
    139  1.1  christos #define RELEASE(x, object_type) object_type ## _finalize(x)
    140  1.1  christos #define RELEASE_HERE(x, object_type) object_type ## _finalize(x)
    141  1.1  christos #define RETAIN(x, object_type)
    142  1.1  christos #define RETAIN_HERE(x, object_tyoe)
    143  1.1  christos #else
    144  1.1  christos #define RELEASE(x, object_type) do {                                          \
    145  1.1  christos         if ((x)->ref_count == 0) {                                            \
    146  1.1  christos             FAULT("ALLOC: release after finalize at %2.2d: %p (%10s): %s:%d", \
    147  1.1  christos                   (x)->ref_count, (void *)(x), # x, FILE_TRIM(file), line);   \
    148  1.1  christos             abort();                                                          \
    149  1.1  christos         }                                                                     \
    150  1.1  christos         if ((x)->ref_count > SRP_OBJ_REF_COUNT_LIMIT) {                       \
    151  1.1  christos             FAULT("ALLOC: release at %2.2d: %p (%10s): %s:%d",                \
    152  1.1  christos                   (x)->ref_count, (void *)(x), # x, FILE_TRIM(file), line);   \
    153  1.1  christos             abort();                                                          \
    154  1.1  christos         }                                                                     \
    155  1.1  christos         if (--(x)->ref_count == 0) {                                          \
    156  1.1  christos             FINALIZED(object_type##_finalized);                               \
    157  1.1  christos             object_type ## _finalize(x);                                      \
    158  1.1  christos             (void)file; (void)line;                                           \
    159  1.1  christos         }                                                                     \
    160  1.1  christos     } while (0)
    161  1.1  christos #define RETAIN(x, object_type) do {                                           \
    162  1.1  christos         (x)->ref_count++;                                                     \
    163  1.1  christos         if (--(x)->ref_count == 0) {                                          \
    164  1.1  christos             CREATED(object_type##_created);                                   \
    165  1.1  christos         }                                                                     \
    166  1.1  christos         if ((x)->ref_count > SRP_OBJ_REF_COUNT_LIMIT) {                       \
    167  1.1  christos             FAULT("ALLOC: retain at %2.2d: %p (%10s): %s:%d",                 \
    168  1.1  christos                   (x)->ref_count, (void *)(x), # x, FILE_TRIM(file), line);   \
    169  1.1  christos             abort();                                                          \
    170  1.1  christos         }                                                                     \
    171  1.1  christos     } while (0)
    172  1.1  christos #define RELEASE_HERE(x, object_type) do {                                     \
    173  1.1  christos         if ((x)->ref_count == 0) {                                            \
    174  1.1  christos             FAULT("ALLOC: release after finalize at %2.2d: %p (%10s)",        \
    175  1.1  christos                   (x)->ref_count, (void *)(x), # x);                          \
    176  1.1  christos             abort();                                                          \
    177  1.1  christos         }                                                                     \
    178  1.1  christos         if ((x)->ref_count > SRP_OBJ_REF_COUNT_LIMIT) {                       \
    179  1.1  christos             FAULT("ALLOC: release at %2.2d: %p (%10s)",                       \
    180  1.1  christos                   (x)->ref_count, (void *)(x), # x);                          \
    181  1.1  christos             abort();                                                          \
    182  1.1  christos         }                                                                     \
    183  1.1  christos         if (--(x)->ref_count == 0) {                                          \
    184  1.1  christos             FINALIZED(object_type##_finalized);                               \
    185  1.1  christos             object_type ## _finalize(x);                                      \
    186  1.1  christos         }                                                                     \
    187  1.1  christos     } while (0)
    188  1.1  christos #define RETAIN_HERE(x, object_type) do {                                      \
    189  1.1  christos         (x)->ref_count++;                                                     \
    190  1.1  christos         if (--(x)->ref_count == 0) {                                          \
    191  1.1  christos             CREATED(object_type##_created);                                   \
    192  1.1  christos         }                                                                     \
    193  1.1  christos         if ((x)->ref_count > SRP_OBJ_REF_COUNT_LIMIT) {                       \
    194  1.1  christos             FAULT("ALLOC: retain at %2.2d: %p (%10s)",                        \
    195  1.1  christos                   (x)->ref_count, (void *)(x), # x);                          \
    196  1.1  christos             abort();                                                          \
    197  1.1  christos         }                                                                     \
    198  1.1  christos     } while (0)
    199  1.1  christos #endif
    200  1.1  christos #endif // DEBUG_VERBOSE
    201  1.1  christos 
    202  1.1  christos #define THREAD_ENTERPRISE_NUMBER ((uint64_t)44970)
    203  1.1  christos #define THREAD_SRP_SERVER_ANYCAST_OPTION 0x5c
    204  1.1  christos #define THREAD_SRP_SERVER_OPTION 0x5d
    205  1.1  christos #define THREAD_PREF_ID_OPTION    0x9d
    206  1.1  christos 
    207  1.1  christos #define IS_SRP_SERVICE(service) \
    208  1.1  christos     ((cti_service)->enterprise_number == THREAD_ENTERPRISE_NUMBER &&    \
    209  1.1  christos      (cti_service)->service_type == THREAD_SRP_SERVER_OPTION &&         \
    210  1.1  christos      (cti_service)->service_version == 1 &&                             \
    211  1.1  christos      (cti_service)->server_length == 18)
    212  1.1  christos #define IS_SRP_ANYCAST_SERVICE(service) \
    213  1.1  christos     ((cti_service)->enterprise_number == THREAD_ENTERPRISE_NUMBER &&    \
    214  1.1  christos      (cti_service)->service_type == THREAD_SRP_SERVER_ANYCAST_OPTION &&         \
    215  1.1  christos      (cti_service)->service_version == 1 &&                             \
    216  1.1  christos      (cti_service)->service_length == 2)
    217  1.1  christos #define IS_PREF_ID_SERVICE(service) \
    218  1.1  christos     ((cti_service)->enterprise_number == THREAD_ENTERPRISE_NUMBER &&    \
    219  1.1  christos      (cti_service)->service_type == THREAD_PREF_ID_OPTION &&            \
    220  1.1  christos      (cti_service)->service_version == 1 &&                             \
    221  1.1  christos      (cti_service)->server_length == 9)
    222  1.1  christos 
    223  1.1  christos #ifdef MALLOC_DEBUG_LOGGING
    224  1.1  christos void *debug_malloc(size_t len, const char *file, int line);
    225  1.1  christos void *debug_calloc(size_t count, size_t len, const char *file, int line);
    226  1.1  christos char *debug_strdup(const char *s, const char *file, int line);
    227  1.1  christos void debug_free(void *p, const char *file, int line);
    228  1.1  christos 
    229  1.1  christos #define malloc(x) debug_malloc(x, __FILE__, __LINE__)
    230  1.1  christos #define calloc(c, y) debug_calloc(c, y, __FILE__, __LINE__)
    231  1.1  christos #define strdup(s) debug_strdup(s, __FILE__, __LINE__)
    232  1.1  christos #define free(p) debug_free(p, __FILE__, __LINE__)
    233  1.1  christos #endif
    234  1.1  christos 
    235  1.1  christos typedef struct srp_key srp_key_t;
    236  1.1  christos 
    237  1.1  christos // This function compares two IPv6 prefixes, up to the specified prefix length (in bytes).
    238  1.1  christos // return: -1 if prefix_a < prefix_b
    239  1.1  christos //          0 if prefix_a == prefix_b
    240  1.1  christos //          1 if prefix_a > prefix_b.
    241  1.1  christos static inline int
    242  1.1  christos in6prefix_compare(const struct in6_addr *prefix_a, const struct in6_addr *prefix_b, size_t len)
    243  1.1  christos {
    244  1.1  christos     return memcmp(prefix_a, prefix_b, len);
    245  1.1  christos }
    246  1.1  christos 
    247  1.1  christos // This function compares two full IPv6 addresses.
    248  1.1  christos // return: -1 if addr_a < addr_b
    249  1.1  christos //          0 if addr_a == addr_b
    250  1.1  christos //          1 if addr_a > addr_b.
    251  1.1  christos static inline int
    252  1.1  christos in6addr_compare(const struct in6_addr *addr_a, const struct in6_addr *addr_b)
    253  1.1  christos {
    254  1.1  christos     return in6prefix_compare(addr_a, addr_b, sizeof (*addr_a));
    255  1.1  christos }
    256  1.1  christos 
    257  1.1  christos // This function copies the data into a, up to len bytes or sizeof(*a), whichever is less.
    258  1.1  christos // if there are uninitialized bytes remaining in a, sets those to zero.
    259  1.1  christos static inline void
    260  1.1  christos in6prefix_copy_from_data(struct in6_addr *prefix, const uint8_t *data, size_t len)
    261  1.1  christos {
    262  1.1  christos     size_t copy_len = sizeof(*prefix) < len ? sizeof(*prefix): len;
    263  1.1  christos     if (copy_len > 0) {
    264  1.1  christos         memcpy(prefix, data, copy_len);
    265  1.1  christos     }
    266  1.1  christos     if (copy_len != sizeof(*prefix)) {
    267  1.1  christos         memset((char *)prefix + copy_len, 0, sizeof(*prefix) - copy_len);
    268  1.1  christos     }
    269  1.1  christos }
    270  1.1  christos 
    271  1.1  christos // This function copies prefix src, into prefix dst, up to len bytes.
    272  1.1  christos static inline void
    273  1.1  christos in6prefix_copy(struct in6_addr *dst, const struct in6_addr *src, size_t len)
    274  1.1  christos {
    275  1.1  christos     in6prefix_copy_from_data(dst, (const uint8_t*)src, len);
    276  1.1  christos }
    277  1.1  christos 
    278  1.1  christos // This function copies full IPv6 address src into dst.
    279  1.1  christos static inline void
    280  1.1  christos in6addr_copy(struct in6_addr *dst, const struct in6_addr *src)
    281  1.1  christos {
    282  1.1  christos     memcpy(dst, src, sizeof(*dst));
    283  1.1  christos }
    284  1.1  christos 
    285  1.1  christos // This function zeros the full IPv6 address
    286  1.1  christos static inline void
    287  1.1  christos in6addr_zero(struct in6_addr *addr)
    288  1.1  christos {
    289  1.1  christos     memset(addr, 0, sizeof(*addr));
    290  1.1  christos }
    291  1.1  christos 
    292  1.1  christos // Returns true if this is a Thread mesh-local anycast address.
    293  1.1  christos extern const uint8_t thread_anycast_preamble[7];
    294  1.1  christos extern const uint8_t thread_rloc_preamble[6];
    295  1.1  christos 
    296  1.1  christos static inline bool
    297  1.1  christos is_thread_mesh_anycast_address(const struct in6_addr *addr)
    298  1.1  christos {
    299  1.1  christos     // Thread 1.3.0 section 5.2.2.2 Anycast Locator (ALOC)
    300  1.1  christos     if (!memcmp(&addr->s6_addr[8], thread_anycast_preamble, sizeof(thread_anycast_preamble))) {
    301  1.1  christos         return true;
    302  1.1  christos     }
    303  1.1  christos     return false;
    304  1.1  christos }
    305  1.1  christos 
    306  1.1  christos static inline bool
    307  1.1  christos is_thread_mesh_rloc_address(const struct in6_addr *addr)
    308  1.1  christos {
    309  1.1  christos     // Thread 1.3.0 section 5.2.2.1 Routing Locator (RLOC)
    310  1.1  christos     if (!memcmp(&addr->s6_addr[8], thread_rloc_preamble, sizeof(thread_rloc_preamble))) {
    311  1.1  christos         return true;
    312  1.1  christos     }
    313  1.1  christos     return false;
    314  1.1  christos }
    315  1.1  christos 
    316  1.1  christos static inline bool
    317  1.1  christos is_thread_mesh_synthetic_address(const struct in6_addr *addr)
    318  1.1  christos {
    319  1.1  christos     return is_thread_mesh_anycast_address(addr) || is_thread_mesh_rloc_address(addr);
    320  1.1  christos }
    321  1.1  christos 
    322  1.1  christos static inline bool
    323  1.1  christos is_thread_mesh_synthetic_or_link_local(const struct in6_addr *addr)
    324  1.1  christos {
    325  1.1  christos     return (is_thread_mesh_anycast_address(addr) || is_thread_mesh_rloc_address(addr) ||
    326  1.1  christos             (addr->s6_addr[0] == 0xfe && (addr->s6_addr[1] & 0xc0) == 0x80));
    327  1.1  christos }
    328  1.1  christos 
    329  1.1  christos #ifndef _SRP_STRICT_DISPOSE_TEMPLATE
    330  1.1  christos     #define _SRP_STRICT_DISPOSE_TEMPLATE(PTR, FUNCTION) \
    331  1.1  christos         do {                                            \
    332  1.1  christos             if (*(PTR) != NULL) {                       \
    333  1.1  christos                 FUNCTION(*PTR);                         \
    334  1.1  christos                 *(PTR) = NULL;                          \
    335  1.1  christos             }                                           \
    336  1.1  christos         } while(0)
    337  1.1  christos #endif
    338  1.1  christos 
    339  1.1  christos #ifndef DNSServiceRefSourceForget
    340  1.1  christos     #define DNSServiceRefSourceForget(PTR) _SRP_STRICT_DISPOSE_TEMPLATE(PTR, DNSServiceRefDeallocate)
    341  1.1  christos #endif
    342  1.1  christos 
    343  1.1  christos 
    344  1.1  christos /*!
    345  1.1  christos  *  @brief
    346  1.1  christos  *      Check the required condition, if the required condition is not met go to the label specified.
    347  1.1  christos  *
    348  1.1  christos  *  @param ASSERTION
    349  1.1  christos  *      The condition that must be met before continue.
    350  1.1  christos  *
    351  1.1  christos  *  @param EXCEPTION_LABEL
    352  1.1  christos  *      The label to go to when the required condition ASSERTION is not met.
    353  1.1  christos  *
    354  1.1  christos  *  @param ACTION
    355  1.1  christos  *      The extra action to take before go to the EXCEPTION_LABEL label when ASSERTION is not met.
    356  1.1  christos  *
    357  1.1  christos  *  @discussion
    358  1.1  christos  *      Example:
    359  1.1  christos  *      require_action_quiet(
    360  1.1  christos  *          foo == NULL, // required to be true
    361  1.1  christos  *          exit, // if not met goto label
    362  1.1  christos  *          ret = -1;  ERROR("foo should not be NULL") // before exiting
    363  1.1  christos  *      ) ;
    364  1.1  christos  */
    365  1.1  christos #ifndef require_action_quiet
    366  1.1  christos     #define require_action_quiet(ASSERTION, EXCEPTION_LABEL, ACTION)    \
    367  1.1  christos         do {                                                            \
    368  1.1  christos             if (__builtin_expect(!(ASSERTION), 0))                      \
    369  1.1  christos             {                                                           \
    370  1.1  christos                 {                                                       \
    371  1.1  christos                     ACTION;                                             \
    372  1.1  christos                 }                                                       \
    373  1.1  christos                 goto EXCEPTION_LABEL;                                   \
    374  1.1  christos             }                                                           \
    375  1.1  christos         } while(0)
    376  1.1  christos #endif // #ifndef require_action
    377  1.1  christos 
    378  1.1  christos #ifndef require_quiet
    379  1.1  christos     #define require_quiet(ASSERTION, EXCEPTION_LABEL)                   \
    380  1.1  christos         do {                                                            \
    381  1.1  christos             if (__builtin_expect(!(ASSERTION), 0))                      \
    382  1.1  christos             {                                                           \
    383  1.1  christos                 goto EXCEPTION_LABEL;                                   \
    384  1.1  christos             }                                                           \
    385  1.1  christos         } while(0)
    386  1.1  christos #endif // #ifndef require_action
    387  1.1  christos 
    388  1.1  christos /*!
    389  1.1  christos  *  @brief
    390  1.1  christos  *      Check the required condition, if the required condition is not met go to the label specified.
    391  1.1  christos  *
    392  1.1  christos  *  @param ASSERTION
    393  1.1  christos  *      The condition that must be met before continue.
    394  1.1  christos  *
    395  1.1  christos  *  @param EXCEPTION_LABEL
    396  1.1  christos  *      The label to go to when the required condition ASSERTION is not met.
    397  1.1  christos  *
    398  1.1  christos  *  @param ACTION
    399  1.1  christos  *      The extra action to take before go to the EXCEPTION_LABEL label when ASSERTION is not met.
    400  1.1  christos  *
    401  1.1  christos  *  @discussion
    402  1.1  christos  *      Example:
    403  1.1  christos  *      require_action(
    404  1.1  christos  *          foo == NULL, // required to be true
    405  1.1  christos  *          exit, // if not met goto label
    406  1.1  christos  *          ret = -1;  ERROR("foo should not be NULL") // before exiting
    407  1.1  christos  *      ) ;
    408  1.1  christos  */
    409  1.1  christos #ifndef require_action
    410  1.1  christos     #define require_action(ASSERTION, EXCEPTION_LABEL, ACTION)    \
    411  1.1  christos         do {                                                            \
    412  1.1  christos             if (__builtin_expect(!(ASSERTION), 0))                      \
    413  1.1  christos             {                                                           \
    414  1.1  christos                 {                                                       \
    415  1.1  christos                     ACTION;                                             \
    416  1.1  christos                 }                                                       \
    417  1.1  christos                 goto EXCEPTION_LABEL;                                   \
    418  1.1  christos             }                                                           \
    419  1.1  christos         } while(0)
    420  1.1  christos #endif // #ifndef require_action
    421  1.1  christos 
    422  1.1  christos /*!
    423  1.1  christos  *  @brief
    424  1.1  christos  *      Check the required condition, if the required condition is not met, do the ACTION. It is usually used as DEBUG macro.
    425  1.1  christos  *
    426  1.1  christos  *  @param ASSERTION
    427  1.1  christos  *      The condition that must be met before continue.
    428  1.1  christos  *
    429  1.1  christos  *  @param ACTION
    430  1.1  christos  *      The extra action to take when ASSERTION is not met.
    431  1.1  christos  *
    432  1.1  christos  *  @discussion
    433  1.1  christos  *      Example:
    434  1.1  christos  *      verify_action(
    435  1.1  christos  *          foo == NULL, // required to be true
    436  1.1  christos  *          ERROR("foo should not be NULL")  // action to take if required is false
    437  1.1  christos  *      ) ;
    438  1.1  christos  */
    439  1.1  christos #undef verify_action
    440  1.1  christos #define verify_action(ASSERTION, ACTION)                                \
    441  1.1  christos     if (__builtin_expect(!(ASSERTION), 0)) {                            \
    442  1.1  christos         ACTION;                                                         \
    443  1.1  christos     }                                                                   \
    444  1.1  christos     else do {} while (0)
    445  1.1  christos 
    446  1.1  christos // Print true or false based on boolean value:
    447  1.1  christos     static inline const char *bool_str(bool tf) {
    448  1.1  christos         if (tf) return "true";
    449  1.1  christos         return "false";
    450  1.1  christos     }
    451  1.1  christos 
    452  1.1  christos 
    453  1.1  christos #ifdef __cplusplus
    454  1.1  christos } // extern "C"
    455  1.1  christos #endif
    456  1.1  christos 
    457  1.1  christos #ifndef THREAD_DEVKIT_ADK
    458  1.1  christos // Object type external definitions
    459  1.1  christos #define OBJECT_TYPE(x) extern int x##_created, x##_finalized, old_##x##_created, old_##x##_finalized;
    460  1.1  christos #include "object-types.h"
    461  1.1  christos #endif // !THREAD_DEVKIT_ADK
    462  1.1  christos 
    463  1.1  christos #endif // __SRP_H
    464  1.1  christos 
    465  1.1  christos // Local Variables:
    466  1.1  christos // mode: C
    467  1.1  christos // tab-width: 4
    468  1.1  christos // c-file-style: "bsd"
    469  1.1  christos // c-basic-offset: 4
    470  1.1  christos // fill-column: 108
    471  1.1  christos // indent-tabs-mode: nil
    472  1.1  christos // End:
    473