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 #include <stdlib.h>
     22 #include <string.h>
     23 #include <stdio.h>
     24 #include <unistd.h>
     25 #include <pwd.h>
     26 #include <errno.h>
     27 #include <sys/socket.h>
     28 #include <netinet/in.h>
     29 #include <arpa/inet.h>
     30 #include <fcntl.h>
     31 #include <time.h>
     32 #include <dns_sd.h>
     33 #include <net/if.h>
     34 #include <inttypes.h>
     35 #include <sys/resource.h>
     36 
     37 #include "srp.h"
     38 #include "dns-msg.h"
     39 #include "srp-crypto.h"
     40 #include "ioloop.h"
     41 #include "srp-gw.h"
     42 #include "srp-proxy.h"
     43 #include "srp-mdns-proxy.h"
     44 #include "dnssd-proxy.h"
     45 #include "config-parse.h"
     46 #include "cti-services.h"
     47 #include "route.h"
     48 #include "state-machine.h"
     49 
     50 #ifdef DEBUG
     51 #define STATE_DEBUGGING_ABORT() abort();
     52 #else
     53 #define STATE_DEBUGGING_ABORT()
     54 #endif
     55 
     56 static state_machine_decl_t *
     57 state_machine_state_get(state_machine_header_t *header, state_machine_state_t state)
     58 {
     59     if (!header->once) {
     60         for (size_t i = 0; i < header->num_states; i++) {
     61             if (header->states[i].state != (state_machine_state_t)i) {
     62                 ERROR(PUB_S_SRP "/" PRI_S_SRP " state %zu doesn't match " PUB_S_SRP,
     63 					  header->state_machine_type_name, header->name, i, header->states[i].name);
     64                 STATE_DEBUGGING_ABORT();
     65                 return NULL;
     66             }
     67         }
     68         header->once = true;
     69     }
     70     if ((size_t)state < 0 || (size_t)state >= header->num_states) {
     71         STATE_DEBUGGING_ABORT();
     72         return NULL;
     73     }
     74     return &header->states[state];
     75 }
     76 
     77 void
     78 state_machine_next_state(state_machine_header_t *state_header, state_machine_state_t state)
     79 {
     80     state_machine_state_t next_state = state;
     81 
     82     do {
     83         state_machine_decl_t *new_state = state_machine_state_get(state_header, next_state);
     84 
     85         if (new_state == NULL) {
     86 			ERROR(PUB_S_SRP "/" PRI_S_SRP " next state is invalid: %d",
     87 				  state_header->state_machine_type_name, state_header->name, next_state);
     88             STATE_DEBUGGING_ABORT();
     89             return;
     90         }
     91         state_header->state = next_state;
     92         state_header->state_name = new_state->name;
     93         state_machine_action_t action = new_state->action;
     94         if (action != NULL) {
     95             next_state = action(state_header, NULL);
     96         }
     97     } while (next_state != state_machine_state_invalid);
     98 }
     99 
    100 void
    101 state_machine_event_finalize(state_machine_event_t *event)
    102 {
    103 	if (event->finalize != NULL) {
    104 		event->finalize(event);
    105 	}
    106 	free(event);
    107 }
    108 
    109 RELEASE_RETAIN_FUNCS(state_machine_event);
    110 
    111 typedef struct {
    112     state_machine_event_type_t event_type;
    113     char *name;
    114 } state_machine_event_configuration_t;
    115 
    116 #define EVENT_NAME_DECL(name) { state_machine_event_type_##name, #name }
    117 
    118 state_machine_event_configuration_t state_machine_event_configurations[] = {
    119     EVENT_NAME_DECL(invalid),
    120     EVENT_NAME_DECL(timeout),
    121     EVENT_NAME_DECL(prefix),
    122     EVENT_NAME_DECL(dhcp),
    123     EVENT_NAME_DECL(service_list_changed),
    124     EVENT_NAME_DECL(listener_ready),
    125     EVENT_NAME_DECL(listener_canceled),
    126     EVENT_NAME_DECL(ml_eid_changed),
    127     EVENT_NAME_DECL(rloc_changed),
    128     EVENT_NAME_DECL(thread_network_state_changed),
    129     EVENT_NAME_DECL(thread_node_type_changed),
    130     EVENT_NAME_DECL(probe_completed),
    131     EVENT_NAME_DECL(got_mesh_local_prefix),
    132     EVENT_NAME_DECL(daemon_disconnect),
    133     EVENT_NAME_DECL(stop),
    134     EVENT_NAME_DECL(dns_registration_invalidated),
    135     EVENT_NAME_DECL(thread_interface_changed),
    136     EVENT_NAME_DECL(wed_ml_eid_changed),
    137     EVENT_NAME_DECL(neighbor_ml_eid_changed),
    138     EVENT_NAME_DECL(srp_needed),
    139     EVENT_NAME_DECL(dns_registration_bad_service),
    140 };
    141 #define STATE_MACHINE_NUM_EVENT_TYPES (sizeof(state_machine_event_configurations) / sizeof(state_machine_event_configuration_t))
    142 
    143 static state_machine_event_configuration_t *
    144 state_machine_event_configuration_get(state_machine_event_type_t event)
    145 {
    146     static bool once = false;
    147     if (!once) {
    148         for (unsigned i = 0; i < STATE_MACHINE_NUM_EVENT_TYPES; i++) {
    149             if (state_machine_event_configurations[i].event_type != (state_machine_event_type_t)i) {
    150                 ERROR("event %d doesn't match " PUB_S_SRP, i, state_machine_event_configurations[i].name);
    151                 STATE_DEBUGGING_ABORT();
    152                 return NULL;
    153             }
    154         }
    155         once = true;
    156     }
    157     if (event < 0 || event >= STATE_MACHINE_NUM_EVENT_TYPES) {
    158         STATE_DEBUGGING_ABORT();
    159         return NULL;
    160     }
    161     return &state_machine_event_configurations[event];
    162 }
    163 
    164 #if 0
    165 static const char *
    166 state_machine_state_name(state_machine_header_t *header, state_machine_state_t state)
    167 {
    168     for (size_t i = 0; i < header->num_states; i++) {
    169         if (header->states[i].state == state) {
    170             return header->states[i].name;
    171         }
    172     }
    173     return "unknown state";
    174 }
    175 #endif
    176 
    177 void
    178 state_machine_event_deliver(state_machine_header_t *state_header, state_machine_event_t *event)
    179 {
    180     state_machine_decl_t *state = state_machine_state_get(state_header, state_header->state);
    181     if (state == NULL) {
    182         ERROR(PUB_S_SRP "/" PRI_S_SRP ": event " PUB_S_SRP " received in invalid state %d",
    183               state_header->state_machine_type_name, state_header->name, event->name, state_header->state);
    184         STATE_DEBUGGING_ABORT();
    185         return;
    186     }
    187     if (state->action == NULL) {
    188         FAULT(PUB_S_SRP "/" PRI_S_SRP ": event " PUB_S_SRP " received in state " PUB_S_SRP " with NULL action",
    189               state_header->state_machine_type_name, state_header->name, event->name, state->name);
    190         return;
    191     }
    192     state_machine_state_t next_state = state->action(state_header, event);
    193     if (next_state != state_machine_state_invalid) {
    194         state_machine_next_state(state_header, next_state);
    195     }
    196 }
    197 
    198 state_machine_event_t *
    199 state_machine_event_create(state_machine_event_type_t type,
    200 						   state_machine_event_finalize_callback_t finalize_callback)
    201 {
    202     state_machine_event_configuration_t *event_config = state_machine_event_configuration_get(type);
    203     if (event_config == NULL) {
    204         ERROR("invalid event type %d", type);
    205         STATE_DEBUGGING_ABORT();
    206         return NULL;
    207     }
    208 	state_machine_event_t *event = calloc(1, sizeof (*event));
    209     event->type = type;
    210     event->name = event_config->name;
    211 	RETAIN_HERE(event, state_machine_event);
    212 	event->finalize = finalize_callback;
    213 	return event;
    214 }
    215 
    216 typedef struct state_machine_type_decl {
    217 	state_machine_type_t state_machine_type;
    218 	const char *state_machine_type_name;
    219 } state_machine_type_decl_t;
    220 
    221 #define STATE_NAME_DECL(name) { state_machine_type_##name, #name }
    222 state_machine_type_decl_t state_machine_types[] = {
    223     STATE_NAME_DECL(invalid),
    224 	STATE_NAME_DECL(omr_publisher),
    225     STATE_NAME_DECL(service_publisher),
    226     STATE_NAME_DECL(dnssd_client),
    227 };
    228 #define STATE_MACHINE_NUM_TYPES (sizeof(state_machine_types) / sizeof(state_machine_type_decl_t))
    229 
    230 bool
    231 state_machine_header_setup(state_machine_header_t *state_header, void *state_object, const char *name,
    232 						   state_machine_type_t type, state_machine_decl_t *states, size_t num_states)
    233 {
    234 	memset(state_header, 0, sizeof(*state_header));
    235 	for (unsigned i = 0; i < STATE_MACHINE_NUM_TYPES; i++) {
    236 		if (state_machine_types[i].state_machine_type == type) {
    237 			state_header->state_machine_type_name = state_machine_types[i].state_machine_type_name;
    238 			break;
    239 		}
    240 	}
    241 	if (state_header->state_machine_type_name == NULL) {
    242 		return false;
    243 	}
    244 	state_header->state_object = state_object;
    245 	state_header->name = strdup(name);
    246 	if (state_header->name == NULL) {
    247 		return false;
    248 	}
    249 	state_header->state_machine_type = type;
    250 	state_header->states = states;
    251 	state_header->num_states = num_states;
    252 	return true;
    253 }
    254 
    255 void state_machine_cancel(state_machine_header_t *NONNULL state_header)
    256 {
    257     INFO("canceling " PUB_S_SRP, state_header->name);
    258     state_header->state = state_machine_state_invalid;
    259 }
    260 
    261 // Local Variables:
    262 // mode: C
    263 // tab-width: 4
    264 // c-file-style: "bsd"
    265 // c-basic-offset: 4
    266 // fill-column: 120
    267 // indent-tabs-mode: nil
    268 // End:
    269