Home | History | Annotate | Line # | Download | only in ServiceRegistration
      1 /* ioloop.h
      2  *
      3  * Copyright (c) 2018-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  * Definitions for simple dispatch implementation.
     18  */
     19 
     20 #ifndef __IOLOOP_H
     21 #define __IOLOOP_H
     22 
     23 
     24 #include <sys/socket.h>
     25 #include <netinet/in.h>
     26 #include <sys/un.h>
     27 
     28 #include <dns_sd.h>
     29 
     30 #ifndef NSEC_PER_SEC
     31 #define NSEC_PER_SEC  1000000000ull
     32 #endif
     33 #ifndef NSEC_PER_MSEC
     34 #define NSEC_PER_MSEC    1000000ull
     35 #endif
     36 
     37 #ifndef MSEC_PER_SEC
     38 #define MSEC_PER_SEC (NSEC_PER_SEC / NSEC_PER_MSEC)
     39 #endif
     40 
     41 #ifndef IN_LINKLOCAL
     42 #define IN_LINKLOCAL(x) (((uint32_t)(x) & 0xffff0000) == 0xA9FE0000) // 169.254.*
     43 #endif
     44 #ifndef IN_LOOPBACK
     45 #define IN_LOOPBACK(x) (((uint32_t)(x) & 0xff000000) == 0x7f000000) // 127.*
     46 #endif
     47 
     48 #ifndef UDP_LISTENER_USES_CONNECTION_GROUPS
     49 #define UDP_LISTENER_USES_CONNECTION_GROUPS 0
     50 #endif
     51 
     52 #ifndef __DSO_H
     53 typedef struct dso_state dso_state_t;
     54 #endif
     55 
     56 typedef union addr addr_t;
     57 union addr {
     58     struct sockaddr sa;
     59     struct sockaddr_in sin;
     60     struct sockaddr_in6 sin6;
     61     struct {
     62         char len;
     63         char family;
     64         int index;
     65         uint8_t addr[8];
     66     } ether_addr;
     67 };
     68 
     69 #define IOLOOP_NTOP(addr, buf) \
     70     (((addr)->sa.sa_family == AF_INET || (addr)->sa.sa_family == AF_INET6) \
     71      ? (inet_ntop((addr)->sa.sa_family, ((addr)->sa.sa_family == AF_INET \
     72                                         ? (void *)&(addr)->sin.sin_addr \
     73                                         : (void *)&(addr)->sin6.sin6_addr), buf, sizeof buf) != NULL) \
     74     : snprintf(buf, sizeof buf, "Address type %d", (addr)->sa.sa_family))
     75 
     76 struct message {
     77     int ref_count;
     78 #if !defined(IOLOOP_MACOS) || !UDP_LISTENER_USES_CONNECTION_GROUPS
     79     addr_t src;
     80     addr_t local;
     81 #endif
     82     int ifindex;
     83     uint16_t length;
     84     time_t received_time;      // Only for SRP Replication, zero otherwise.
     85     uint32_t lease, key_lease; // For SRP replication, leases agreed to by original registrar
     86     dns_wire_t wire;
     87 };
     88 
     89 
     90 typedef struct dso_transport comm_t;
     91 typedef struct io io_t;
     92 typedef struct subproc subproc_t;
     93 typedef struct wakeup wakeup_t;
     94 typedef struct dnssd_txn dnssd_txn_t;
     95 typedef struct interface_address_state interface_address_state_t;
     96 typedef struct ifpermit_list ifpermit_list_t;
     97 
     98 typedef void (*dnssd_txn_finalize_callback_t)(void *NONNULL context);
     99 typedef void (*dnssd_txn_failure_callback_t)(void *NONNULL context, int status);
    100 typedef void (*wakeup_callback_t)(void *NONNULL context);
    101 typedef void (*finalize_callback_t)(void *NONNULL context);
    102 typedef void (*cancel_callback_t)(comm_t *NONNULL comm, void *NONNULL context);
    103 typedef void (*ready_callback_t)(void *NONNULL context, uint16_t port);
    104 typedef void (*io_callback_t)(io_t *NONNULL io, void *NONNULL context);
    105 typedef void (*comm_callback_t)(comm_t *NONNULL comm);
    106 typedef void (*datagram_callback_t)(comm_t *NONNULL comm, message_t *NONNULL message, void *NULLABLE context);
    107 typedef void (*connect_callback_t)(comm_t *NONNULL connection, void *NULLABLE context);
    108 typedef void (*disconnect_callback_t)(comm_t *NONNULL comm, void *NULLABLE context, int error);
    109 enum interface_address_change { interface_address_added, interface_address_deleted, interface_address_unchanged };
    110 typedef struct srp_server_state srp_server_t;
    111 typedef void (*interface_callback_t)(srp_server_t *NULLABLE server_state, void *NULLABLE context,
    112                                      const char *NONNULL name, const addr_t *NONNULL address,
    113                                      const addr_t *NONNULL netmask, uint32_t flags,
    114                                      enum interface_address_change event_type);
    115 typedef void (*subproc_callback_t)(void *NULLABLE context, int status, const char *NULLABLE error);
    116 typedef void (*tls_config_callback_t)(void *NONNULL context);
    117 typedef void (*async_callback_t)(void *NULLABLE context);
    118 
    119 typedef struct tls_context tls_context_t;
    120 
    121 #define IOLOOP_SECOND   1000LL
    122 #define IOLOOP_MINUTE   60 * IOLOOP_SECOND
    123 #define IOLOOP_HOUR     60 * IOLOOP_MINUTE
    124 #define IOLOOP_DAY      24 * IOLOOP_HOUR
    125 
    126 struct interface_address_state {
    127     interface_address_state_t *NULLABLE next;
    128     char *NONNULL name;
    129     addr_t addr;
    130     addr_t mask;
    131     uint32_t flags;
    132 };
    133 
    134 struct io {
    135     int ref_count;
    136     io_t *NULLABLE next;
    137     io_callback_t NULLABLE read_callback;
    138     io_callback_t NULLABLE write_callback;
    139     finalize_callback_t NULLABLE finalize;
    140     finalize_callback_t NULLABLE io_finalize;
    141     finalize_callback_t NULLABLE context_release;
    142     void *NULLABLE context;
    143     io_t *NULLABLE cancel_on_close;
    144     io_callback_t NULLABLE ready;
    145     bool want_read : 1;
    146     bool want_write : 1;
    147     int fd;
    148 };
    149 
    150 struct wakeup {
    151     int ref_count;
    152     wakeup_t *NULLABLE next;
    153     void *NULLABLE context;
    154     wakeup_callback_t NULLABLE wakeup;
    155     finalize_callback_t NULLABLE finalize;
    156 #ifdef IOLOOP_MACOS
    157     dispatch_source_t NULLABLE dispatch_source;
    158 #else
    159     int64_t wakeup_time;
    160 #endif
    161 };
    162 
    163 struct dso_transport {
    164 #ifdef IOLOOP_MACOS
    165     nw_connection_t NULLABLE connection;
    166     nw_listener_t NULLABLE listener;
    167 #if UDP_LISTENER_USES_CONNECTION_GROUPS
    168     nw_connection_group_t NULLABLE connection_group;
    169     nw_content_context_t NULLABLE content_context;
    170 #endif
    171     nw_parameters_t NULLABLE parameters;
    172     comm_t *NULLABLE listener_state;
    173     int ref_count;
    174     int writes_pending;
    175     wakeup_t *NULLABLE idle_timer;
    176     // nw_connection objects aren't necessarily ready to write to immediately. But when we create an outgoing connection, we
    177     // typically want to write to it immediately. So we have a one-datum queue in case this happens; if the connection takes
    178     // so long to get ready that another write happens, we drop the first write. This will work okay for UDP connections, where
    179     // the retransmit logic is in the application. For future, we may want to rearchitect the flow so that the write is always
    180     // done in a callback.
    181     dispatch_data_t NULLABLE pending_write;
    182 #if !UDP_LISTENER_USES_CONNECTION_GROUPS
    183     io_t io;
    184     message_t *NULLABLE message;
    185 #endif
    186 #else
    187     io_t io;
    188     message_t *NULLABLE message;
    189     int multicast_ifindex;
    190 #endif
    191     uint16_t listen_port;
    192     uint16_t *NULLABLE avoid_ports;
    193     int num_avoid_ports;
    194     int serial;
    195     bool avoiding;
    196     char *NONNULL name;
    197     void *NULLABLE context;
    198 #ifdef SRP_TEST_SERVER
    199     void *NULLABLE test_context;
    200     bool (*NULLABLE test_send_intercept)(comm_t *NONNULL connection, message_t *NULLABLE responding_to,
    201                                          struct iovec *NONNULL iov, int iov_len, bool final, bool send_length);
    202     void *NULLABLE srp_server;
    203 #endif
    204     datagram_callback_t NULLABLE datagram_callback;
    205     comm_callback_t NULLABLE close_callback;
    206     connect_callback_t NULLABLE connected;
    207     disconnect_callback_t NULLABLE disconnected;
    208     finalize_callback_t NULLABLE finalize;
    209     cancel_callback_t NULLABLE cancel;
    210     ready_callback_t NULLABLE ready;
    211     uint8_t *NULLABLE buf;
    212     dso_state_t *NULLABLE dso;
    213     tls_context_t *NULLABLE tls_context;
    214     addr_t address, multicast, local;
    215     size_t message_length_len;
    216     size_t message_length, message_cur;
    217     uint8_t message_length_bytes[2];
    218 
    219 
    220 #ifdef IOLOOP_MACOS
    221     bool read_pending: 1; // Only ever one.
    222     bool server: 1;       // Indicates that this connection was created by a listener
    223     bool connection_ready: 1;
    224     bool final_data : 1; // Indicates that the next message written will be the final message, so send a FIN.
    225 #else
    226     bool tls_handshake_incomplete: 1;
    227 #endif // IOLOOP_MACOS
    228     bool tls_rotation_ready: 1; // Indicates if the listener should rotate its TLS certificate.
    229     bool tcp_stream: 1;
    230     bool is_multicast: 1;
    231     bool is_connected: 1;
    232     bool is_listener: 1;
    233     bool opportunistic: 1;
    234     bool canceled: 1;
    235 };
    236 
    237 #define MAX_SUBPROC_ARGS 20
    238 struct subproc {
    239     int ref_count;
    240 #ifdef IOLOOP_MACOS
    241     dispatch_source_t NULLABLE dispatch_source;
    242 #else
    243     subproc_t *NULLABLE next;
    244 #endif
    245     int pipe_fds[2];
    246     io_t *NULLABLE output_fd;
    247     void *NULLABLE context;
    248     subproc_callback_t NONNULL callback;
    249     finalize_callback_t NULLABLE finalize;
    250     char *NULLABLE argv[MAX_SUBPROC_ARGS + 1];
    251     int argc;
    252     pid_t pid;
    253     bool finished : 1;
    254 };
    255 
    256 struct dnssd_txn {
    257 #ifndef IOLOOP_MACOS
    258     io_t *NULLABLE io;
    259 #endif
    260     int ref_count;
    261     DNSServiceRef NULLABLE sdref;
    262     void *NULLABLE context;
    263     void *NULLABLE aux_pointer;
    264     dnssd_txn_finalize_callback_t NULLABLE finalize_callback;
    265     dnssd_txn_failure_callback_t NULLABLE failure_callback;
    266 };
    267 
    268 extern int64_t ioloop_now;
    269 int getipaddr(addr_t *NONNULL addr, const char *NONNULL p);
    270 int64_t ioloop_timenow(void);
    271 message_t *NULLABLE message_allocate(size_t message_size);
    272 void message_free(message_t *NONNULL message);
    273 void ioloop_close(io_t *NONNULL io);
    274 void ioloop_add_reader(io_t *NONNULL io, io_callback_t NONNULL callback);
    275 #define ioloop_wakeup_create() ioloop_wakeup_create_(__FILE__, __LINE__)
    276 wakeup_t *NULLABLE ioloop_wakeup_create_(const char *NONNULL file, int line);
    277 #define ioloop_wakeup_retain(wakeup) ioloop_wakeup_retain_(wakeup, __FILE__, __LINE__)
    278 void ioloop_wakeup_retain_(wakeup_t *NONNULL wakeup, const char *NONNULL file, int line);
    279 #define ioloop_wakeup_release(wakeup) ioloop_wakeup_release_(wakeup, __FILE__, __LINE__)
    280 #ifndef ioloop_wakeup_forget
    281     #define ioloop_wakeup_forget(ptr) _SRP_STRICT_DISPOSE_TEMPLATE(ptr, ioloop_wakeup_release)
    282 #endif
    283 void ioloop_wakeup_release_(wakeup_t *NONNULL wakeup, const char *NONNULL file, int line);
    284 bool ioloop_add_wake_event(wakeup_t *NONNULL wakeup, void *NULLABLE context,
    285                            wakeup_callback_t NONNULL callback, finalize_callback_t NULLABLE finalize,
    286                            int32_t milliseconds);
    287 void ioloop_cancel_wake_event(wakeup_t *NONNULL wakeup);
    288 
    289 bool ioloop_init(void);
    290 int ioloop(void);
    291 
    292 #define ioloop_comm_retain(comm) ioloop_comm_retain_(comm, __FILE__, __LINE__)
    293 void ioloop_comm_retain_(comm_t *NONNULL comm, const char *NONNULL file, int line);
    294 #define ioloop_comm_release(wakeup) ioloop_comm_release_(wakeup, __FILE__, __LINE__)
    295 void ioloop_comm_release_(comm_t *NONNULL comm, const char *NONNULL file, int line);
    296 void ioloop_comm_context_set(comm_t *NONNULL connection,
    297                              void *NULLABLE context, finalize_callback_t NULLABLE callback);
    298 void ioloop_comm_connect_callback_set(comm_t *NONNULL comm, connect_callback_t NULLABLE callback);
    299 void ioloop_comm_disconnect_callback_set(comm_t *NONNULL comm, disconnect_callback_t NULLABLE callback);
    300 void ioloop_comm_cancel(comm_t *NONNULL comm);
    301 #define ioloop_listener_retain(comm) ioloop_listener_retain_(comm, __FILE__, __LINE__)
    302 void ioloop_listener_retain_(comm_t *NONNULL listener, const char *NONNULL file, int line);
    303 #define ioloop_listener_release(wakeup) ioloop_listener_release_(wakeup, __FILE__, __LINE__)
    304 void ioloop_listener_release_(comm_t *NONNULL listener, const char *NONNULL file, int line);
    305 void ioloop_listener_cancel(comm_t *NONNULL comm);
    306 comm_t *NULLABLE ioloop_listener_create(bool stream, bool tls, bool init_daemon, uint16_t *NULLABLE avoid_ports,
    307                                         int num_avoid_ports, const addr_t *NULLABLE ip_address,
    308                                         const char *NULLABLE multicast, const char *NONNULL name,
    309                                         datagram_callback_t NONNULL datagram_callback,
    310                                         connect_callback_t NULLABLE connected, cancel_callback_t NULLABLE cancel,
    311                                         ready_callback_t NULLABLE ready, finalize_callback_t NULLABLE finalize,
    312                                         tls_config_callback_t NULLABLE tls_config, unsigned ifindex,
    313                                         void *NULLABLE context);
    314 comm_t *NULLABLE ioloop_connection_create(addr_t *NONNULL remote_address, bool tls, bool stream, bool stable,
    315                                           bool opportunistic, datagram_callback_t NONNULL datagram_callback,
    316                                           connect_callback_t NULLABLE connected,
    317                                           disconnect_callback_t NULLABLE disconnected,
    318                                           finalize_callback_t NULLABLE finalize,
    319                                           void *NULLABLE context);
    320 #define ioloop_message_create(x) ioloop_message_create_(x, __FILE__, __LINE__)
    321 message_t *NULLABLE ioloop_message_create_(size_t message_size, const char *NONNULL file, int line);
    322 #define ioloop_message_retain(wakeup) ioloop_message_retain_(wakeup, __FILE__, __LINE__)
    323 void ioloop_message_retain_(message_t *NONNULL message, const char *NONNULL file, int line);
    324 #define ioloop_message_release(wakeup) ioloop_message_release_(wakeup, __FILE__, __LINE__)
    325 void ioloop_message_release_(message_t *NONNULL message, const char *NONNULL file, int line);
    326 bool ioloop_send_multicast(comm_t *NONNULL comm, int ifindex, struct iovec *NONNULL iov, int iov_len);
    327 bool ioloop_send_message(comm_t *NONNULL connection, message_t *NULLABLE responding_to,
    328                          struct iovec *NONNULL iov, int iov_len);
    329 bool ioloop_send_final_message(comm_t *NONNULL connection, message_t *NULLABLE responding_to,
    330                                struct iovec *NONNULL iov, int iov_len);
    331 bool ioloop_send_data(comm_t *NONNULL connection, message_t *NULLABLE responding_to,
    332                       struct iovec *NONNULL iov, int iov_len);
    333 bool ioloop_send_final_data(comm_t *NONNULL connection, message_t *NULLABLE responding_to,
    334                             struct iovec *NONNULL iov, int iov_len);
    335 void ioloop_dump_object_allocation_stats(void);
    336 void ioloop_strcpy(char *NONNULL dest, const char *NONNULL src, size_t lim);
    337 bool ioloop_map_interface_addresses(srp_server_t *NULLABLE server_state,
    338                                     const char *NULLABLE ifname, void *NULLABLE context, interface_callback_t NULLABLE callback);
    339 #define ioloop_map_interface_addresses_here(server_state, here, ifname, context, callback) \
    340     ioloop_map_interface_addresses_here_(server_state, here, ifname, context, callback, __FILE__, __LINE__)
    341 bool ioloop_map_interface_addresses_here_(srp_server_t *NULLABLE server_state,
    342                                           interface_address_state_t *NONNULL *NULLABLE here,
    343                                           const char *NULLABLE ifname,
    344                                           void *NULLABLE context, interface_callback_t NULLABLE callback,
    345                                           const char *NONNULL file, int line);
    346 ssize_t ioloop_recvmsg(int sock, uint8_t *NONNULL buffer, size_t buffer_length, int *NONNULL ifindex,
    347                        int *NONNULL hoplimit, addr_t *NONNULL source, addr_t *NONNULL destination);
    348 #define ioloop_subproc_release(subproc) ioloop_subproc_release_(subproc, __FILE__, __LINE__)
    349 void ioloop_subproc_release_(subproc_t *NONNULL subproc, const char *NONNULL file, int line);
    350 #define ioloop_subproc_retain(subproc) ioloop_subproc_retain_(subproc, __FILE__, __LINE__)
    351 void ioloop_subproc_retain_(subproc_t *NONNULL subproc, const char *NONNULL file, int line);
    352 subproc_t *NULLABLE ioloop_subproc(const char *NONNULL exepath, char *NULLABLE *NONNULL argv, int argc,
    353                                    subproc_callback_t NULLABLE callback, io_callback_t NULLABLE output_callback,
    354                                    void *NULLABLE context);
    355 void ioloop_subproc_run_sync(subproc_t *NONNULL subproc);
    356 #define ioloop_dnssd_txn_add(ref, context, finalize_callback, failure_callback) \
    357     ioloop_dnssd_txn_add_(ref, context, finalize_callback, failure_callback, __FILE__, __LINE__)
    358 dnssd_txn_t *NULLABLE
    359 ioloop_dnssd_txn_add_(DNSServiceRef NONNULL ref, void *NULLABLE context,
    360                       dnssd_txn_finalize_callback_t NULLABLE callback,
    361                       dnssd_txn_failure_callback_t NULLABLE failure_callback, const char *NONNULL file, int line);
    362 #define ioloop_dnssd_txn_add_subordinate(ref, context, finalize_callback, failure_callback) \
    363     ioloop_dnssd_txn_add_subordinate_(ref, context, finalize_callback, failure_callback, __FILE__, __LINE__)
    364 dnssd_txn_t *NULLABLE
    365 ioloop_dnssd_txn_add_subordinate_(DNSServiceRef NONNULL ref, void *NULLABLE context,
    366                                   dnssd_txn_finalize_callback_t NULLABLE callback,
    367                                   dnssd_txn_failure_callback_t NULLABLE failure_callback, const char *NONNULL file, int line);
    368 void ioloop_dnssd_txn_cancel(dnssd_txn_t *NONNULL txn);
    369 #define ioloop_dnssd_txn_retain(txn) ioloop_dnssd_txn_retain_(txn, __FILE__, __LINE__)
    370 void ioloop_dnssd_txn_retain_(dnssd_txn_t *NONNULL txn, const char *NONNULL file, int line);
    371 #define ioloop_dnssd_txn_release(txn) ioloop_dnssd_txn_release_(txn, __FILE__, __LINE__)
    372 #ifndef ioloop_dnssd_txn_forget
    373     #define ioloop_dnssd_txn_forget(ptr) _SRP_STRICT_DISPOSE_TEMPLATE(ptr, ioloop_dnssd_txn_release)
    374 #endif
    375 void ioloop_dnssd_txn_release_(dnssd_txn_t *NONNULL txn, const char *NONNULL file, int line);
    376 #endif
    377 void ioloop_dnssd_txn_set_aux_pointer(dnssd_txn_t *NONNULL txn, void *NULLABLE aux_pointer);
    378 void *NULLABLE ioloop_dnssd_txn_get_aux_pointer(dnssd_txn_t *NONNULL txn);
    379 void *NULLABLE ioloop_dnssd_txn_get_context(dnssd_txn_t *NONNULL txn);
    380 
    381 #define ioloop_file_descriptor_create(fd, context, finalize) \
    382     ioloop_file_descriptor_create_(fd, context, finalize, __FILE__, __LINE__)
    383 io_t *NULLABLE ioloop_file_descriptor_create_(int fd, void *NULLABLE context, finalize_callback_t NULLABLE finalize,
    384                                               const char *NONNULL file, int line);
    385 #define ioloop_file_descriptor_retain(file_descriptor) ioloop_file_descriptor_retain_(file_descriptor, __FILE__, \
    386                                                             __LINE__)
    387 void ioloop_file_descriptor_retain_(io_t *NONNULL file_descriptor, const char *NONNULL file, int line);
    388 #define ioloop_file_descriptor_release(file_descriptor) ioloop_file_descriptor_release_(file_descriptor, __FILE__, \
    389                                                             __LINE__)
    390 void ioloop_file_descriptor_release_(io_t *NONNULL file_descriptor, const char *NONNULL file, int line);
    391 
    392 bool ioloop_interface_monitor_start(void);
    393 void ioloop_run_async(async_callback_t NULLABLE callback, void *NULLABLE context);
    394 
    395 
    396 bool srp_load_file_data(void *NULLABLE host_context, const char *NONNULL filename, uint8_t *NONNULL buffer,
    397                         uint16_t *NONNULL length, uint16_t buffer_size);
    398 bool srp_store_file_data(void *NULLABLE host_context, const char *NONNULL filename, uint8_t *NONNULL buffer,
    399                          uint16_t length);
    400 time_t srp_time(void);
    401 double srp_fractional_time(void);
    402 int64_t srp_utime(void);
    403 void srp_format_time_offset(char *NONNULL buf, size_t buf_len, time_t offset);
    404 
    405 const struct sockaddr *NULLABLE connection_get_local_address(message_t *NULLABLE message);
    406 
    407 #if !UDP_LISTENER_USES_CONNECTION_GROUPS
    408 bool ioloop_udp_send_message(comm_t *NONNULL comm, addr_t *NULLABLE source, addr_t *NONNULL dest, int ifindex,
    409                              struct iovec *NONNULL iov, int iov_len);
    410 void ioloop_udp_read_callback(io_t *NONNULL io, void *NULLABLE context);
    411 #endif
    412 int get_num_fds(void);
    413 
    414 
    415 // Local Variables:
    416 // mode: C
    417 // tab-width: 4
    418 // c-file-style: "bsd"
    419 // c-basic-offset: 4
    420 // fill-column: 108
    421 // indent-tabs-mode: nil
    422 // End:
    423