Home | History | Annotate | Line # | Download | only in ServiceRegistration
      1 /* state-machine.h
      2  *
      3  * Copyright (c) 2023-2024 Apple Inc. All rights reserved.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     https://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  * This file contains general support definitions for state machines in the Thread Border Router
     18  * implementation.
     19  */
     20 
     21 #ifndef __STATE_MACHINE_H__
     22 #define __STATE_MACHINE_H__ 1
     23 
     24 #define RELEASE_RETAIN_FUNCS(type)                                              \
     25 void                                                                            \
     26 type##_retain_(type##_t * omw, const char *file, int line)                      \
     27 {                                                                               \
     28     RETAIN(omw, type);                                                          \
     29 }                                                                               \
     30                                                                                 \
     31 void                                                                            \
     32 type##_release_(type##_t *NONNULL omw, const char *file, int line)              \
     33 {                                                                               \
     34     RELEASE(omw, type);                                                         \
     35 }
     36 
     37 #define RELEASE_RETAIN_DECLS(type)                                              \
     38 void type##_retain_(type##_t *NONNULL omw, const char *NONNULL file, int line); \
     39 void type##_release_(type##_t *NONNULL omw, const char *NONNULL file, int line);
     40 
     41 // The assumptions below are that every object that holds a state that these macros can operate on has
     42 // the following elements:
     43 //
     44 // name: (char *), NUL terminated, name of object instance
     45 // state_name: (const char *), NUL terminated, name of the state the object is in
     46 // state: the current state of the state machine, as an enum
     47 //
     48 // For macros that take events, the event is assumed to have the following elements:
     49 //
     50 // name: (char *), NUL terminated, name of event type (iow, not specific to an event instance)
     51 
     52 // For states that never receive events.
     53 #define BR_REQUIRE_STATE_OBJECT_EVENT_NULL(state_object, event)                                                        \
     54     do {                                                                                                               \
     55         if ((event) != NULL) {                                                                                         \
     56             ERROR(PUB_S_SRP "/" PRI_S_SRP ": received unexpected " PUB_S_SRP " event in state " PUB_S_SRP,             \
     57                 state_object->state_header.state_machine_type_name,                                                    \
     58                 state_object->state_header.name, event->name, state_object->state_header.state_name);                  \
     59             return state_machine_state_invalid;                                                       	               \
     60         }                                                                                    	                       \
     61     } while (false)
     62 
     63 // Announce that we have entered a state that takes no events
     64 #define BR_STATE_ANNOUNCE_NO_EVENTS(state_object)                                                                      \
     65     do {																							                   \
     66         INFO(PUB_S_SRP "/" PRI_S_SRP ": entering state " PUB_S_SRP, state_object->state_header.name,                   \
     67              state_object->state_header.state_machine_type_name,                                                       \
     68              state_object->state_header.state_name);                                                                   \
     69     } while (false)
     70 
     71 // Announce that we have entered a state that takes no events, and include a domain name
     72 #define BR_STATE_ANNOUNCE_NO_EVENTS_NAME(state_object, fqdn)                                                           \
     73     do {                                                                                                               \
     74         char hostname[kDNSServiceMaxDomainName];                                                                       \
     75         dns_name_print(fqdn, hostname, sizeof(hostname));                                                              \
     76         INFO(PUB_S_SRP "/" PRI_S_SRP ": entering state " PUB_S_SRP " with host " PRI_S_SRP,                            \
     77             state_object->state_header.state_machine_type_name,                                                        \
     78             state_object->state_header.name, state_object->state_header.state_name, hostname);                         \
     79     } while (false)
     80 
     81 // Announce that we have entered a state that takes no events
     82 #define BR_STATE_ANNOUNCE(state_object, event)                                                                         \
     83     do {							 															                       \
     84         if (event != NULL)  {                                                                                          \
     85             INFO(PUB_S_SRP "/" PRI_S_SRP ": event " PUB_S_SRP " received in state " PUB_S_SRP,                         \
     86                  state_object->state_header.state_machine_type_name,                                                   \
     87                  state_object->state_header.name, event->name, state_object->state_header.state_name);                 \
     88         } else {                                                                                                       \
     89             INFO(PUB_S_SRP "/" PRI_S_SRP ": entering state " PUB_S_SRP,                                                \
     90                  state_object->state_header.state_machine_type_name,                                                   \
     91                  state_object->state_header.name, state_object->state_header.state_name);                              \
     92         }                                                                                                              \
     93     } while (false)
     94 
     95 #define BR_UNEXPECTED_EVENT_MAIN(state_object, event, bad, event_is_message)                                           \
     96     do {                                                                                                               \
     97         if (event_is_message(event)) {                                                                                 \
     98             INFO(PUB_S_SRP "/" PRI_S_SRP ": invalid event " PUB_S_SRP " in state " PUB_S_SRP,                          \
     99                  state_object->state_header.state_machine_type_name,                                                   \
    100                  (state_object)->state_header.name, (event)->name, state_object->state_header.state_name);             \
    101             return (int)bad;														                                   \
    102         }                                                                                                              \
    103         INFO(PUB_S_SRP "/" PRI_S_SRP ": unexpected event " PUB_S_SRP " in state " PUB_S_SRP,                           \
    104              state_object->state_header.state_machine_type_name,                                                       \
    105              (state_object)->state_header.name, (event)->name,                                                         \
    106              state_object->state_header.state_name);                                                                   \
    107         return (int)state_machine_state_invalid;                                                                       \
    108     } while (false)
    109 
    110 // UNEXPECTED_EVENT flags the response as bad on a protocol level, triggering a retry delay
    111 // UNEXPECTED_EVENT_NO_ERROR doesn't.
    112 #define BR_UNEXPECTED_EVENT(state_object, event)                                                                       \
    113     BR_UNEXPECTED_EVENT_MAIN(state_object, event, state_machine_state_invalid,                                         \
    114                                                                           state_machine_event_is_message)
    115 #define BR_UNEXPECTED_EVENT_NO_ERROR(state_object, event)                                                              \
    116     BR_UNEXPECTED_EVENT_MAIN(state_object, event, state_object_drop_state(state_object->instance, state_object),       \
    117                           state_machine_event_is_message)
    118 
    119 // Generalized border router event object
    120 
    121 #define state_machine_event_is_message(x) false
    122 
    123 typedef enum {
    124     state_machine_event_type_invalid,
    125     state_machine_event_type_timeout,
    126     state_machine_event_type_prefix,
    127     state_machine_event_type_dhcp,
    128     state_machine_event_type_service_list_changed,
    129     state_machine_event_type_listener_ready,
    130     state_machine_event_type_listener_canceled,
    131     state_machine_event_type_ml_eid_changed,
    132     state_machine_event_type_rloc_changed,
    133     state_machine_event_type_thread_network_state_changed,
    134     state_machine_event_type_thread_node_type_changed,
    135     state_machine_event_type_probe_completed,
    136     state_machine_event_type_got_mesh_local_prefix,
    137     state_machine_event_type_daemon_disconnect,
    138     state_machine_event_type_stop,
    139     state_machine_event_type_dns_registration_invalidated,
    140     state_machine_event_type_thread_interface_changed,
    141     state_machine_event_type_wed_ml_eid_changed,
    142     state_machine_event_type_neighbor_ml_eid_changed,
    143     state_machine_event_type_srp_needed,
    144     state_machine_event_type_dns_registration_bad_service,
    145 } state_machine_event_type_t;
    146 
    147 typedef struct state_machine_event state_machine_event_t;
    148 typedef struct state_machine_header state_machine_header_t;
    149 typedef void (*state_machine_event_finalize_callback_t)(state_machine_event_t *NONNULL event);
    150 typedef struct omr_prefix omr_prefix_t;
    151 struct state_machine_event {
    152 	int ref_count;
    153 	const char *NULLABLE name;
    154     state_machine_event_type_t type;
    155     omr_prefix_t *NULLABLE thread_prefixes;
    156     state_machine_event_finalize_callback_t NULLABLE finalize;
    157 };
    158 
    159 #ifndef STATE_MACHINE_IMPLEMENTATION
    160 typedef enum state_machine_state {
    161 	state_machine_state_invalid = 0,
    162 } state_machine_state_t;
    163 #endif // STATE_MACHINE_IMPLEMENTATION
    164 
    165 typedef state_machine_state_t (*state_machine_action_t)(state_machine_header_t *NONNULL state_header, state_machine_event_t *NULLABLE event);
    166 typedef struct state_machine_state_decl {
    167     state_machine_state_t state;
    168     const char *NONNULL name;
    169     state_machine_action_t NONNULL action;
    170 } state_machine_decl_t;
    171 
    172 typedef enum {
    173     state_machine_type_invalid,
    174     state_machine_type_omr_publisher,
    175     state_machine_type_service_publisher,
    176     state_machine_type_dnssd_client,
    177 } state_machine_type_t;
    178 
    179 struct state_machine_header {
    180 	char *NULLABLE name;
    181     void *NULLABLE state_object;
    182 	const char *NULLABLE state_name;
    183     state_machine_decl_t *NULLABLE states;
    184     const char *NULLABLE state_machine_type_name;
    185     size_t num_states;
    186 	state_machine_state_t state;
    187     state_machine_type_t state_machine_type;
    188     bool once;
    189 };
    190 
    191 void state_machine_next_state(state_machine_header_t *NONNULL state_header, state_machine_state_t state);
    192 void state_machine_event_finalize(state_machine_event_t *NONNULL event);
    193 RELEASE_RETAIN_DECLS(state_machine_event);
    194 state_machine_event_t *NULLABLE
    195 state_machine_event_create(state_machine_event_type_t type,
    196                            state_machine_event_finalize_callback_t NULLABLE finalize_callback);
    197 void state_machine_event_deliver(state_machine_header_t *NONNULL state_header, state_machine_event_t *NONNULL event);
    198 bool state_machine_header_setup(state_machine_header_t *NONNULL state_header, void *NONNULL state_object, const char *NULLABLE name,
    199                                 state_machine_type_t type, state_machine_decl_t *NONNULL states, size_t num_states);
    200 void state_machine_cancel(state_machine_header_t *NONNULL state_header);
    201 #endif // __STATE_MACHINE_H__
    202 
    203 // Local Variables:
    204 // mode: C
    205 // tab-width: 4
    206 // c-file-style: "bsd"
    207 // c-basic-offset: 4
    208 // fill-column: 120
    209 // indent-tabs-mode: nil
    210 // End:
    211