1 /* ioloop.h 2 * 3 * Copyright (c) 2018-2019 Apple Computer, 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 * http://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 #ifdef IOLOOP_MACOS 24 #include <nw/private.h> 25 #include <Network/Network.h> 26 #include <xpc/xpc.h> 27 #include <xpc/private.h> 28 #endif 29 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 #include <net/if_dl.h> 33 34 #ifndef __DSO_H 35 typedef struct dso_state dso_state_t; 36 #endif 37 38 typedef union addr addr_t; 39 union addr { 40 struct sockaddr sa; 41 struct sockaddr_in sin; 42 struct sockaddr_in6 sin6; 43 struct { 44 char len; 45 char family; 46 int index; 47 uint8_t addr[8]; 48 } ether_addr; 49 }; 50 51 #define IOLOOP_NTOP(addr, buf) \ 52 (((addr)->sa.sa_family == AF_INET || (addr)->sa.sa_family == AF_INET6) \ 53 ? (inet_ntop((addr)->sa.sa_family, ((addr)->sa.sa_family == AF_INET \ 54 ? (void *)&(addr)->sin.sin_addr \ 55 : (void *)&(addr)->sin6.sin6_addr), buf, sizeof buf) != NULL) \ 56 : snprintf(buf, sizeof buf, "Address type %d", (addr)->sa.sa_family)) 57 58 struct message { 59 int ref_count; 60 #ifndef IOLOOP_MACOS 61 addr_t src; 62 addr_t local; 63 #endif 64 int ifindex; 65 uint16_t length; 66 dns_wire_t wire; 67 }; 68 69 70 typedef struct dso_transport comm_t; 71 typedef struct io io_t; 72 typedef struct subproc subproc_t; 73 typedef struct wakeup wakeup_t; 74 typedef struct dnssd_txn dnssd_txn_t; 75 76 typedef void (*dnssd_txn_finalize_callback_t)(void *NONNULL context); 77 typedef void (*wakeup_callback_t)(void *NONNULL context); 78 typedef void (*finalize_callback_t)(void *NONNULL context); 79 typedef void (*cancel_callback_t)(void *NONNULL context); 80 typedef void (*ready_callback_t)(void *NONNULL context, uint16_t port); 81 typedef void (*io_callback_t)(io_t *NONNULL io, void *NONNULL context); 82 typedef void (*comm_callback_t)(comm_t *NONNULL comm); 83 typedef void (*datagram_callback_t)(comm_t *NONNULL comm, message_t *NONNULL message, void *NULLABLE context); 84 typedef void (*connect_callback_t)(comm_t *NONNULL connection, void *NULLABLE context); 85 typedef void (*disconnect_callback_t)(comm_t *NONNULL comm, int error); 86 enum interface_address_change { interface_address_added, interface_address_deleted, interface_address_unchanged }; 87 typedef void (*interface_callback_t)(void *NULLABLE context, const char *NONNULL name, 88 const addr_t *NONNULL address, const addr_t *NONNULL netmask, 89 uint32_t flags, enum interface_address_change event_type); 90 typedef void (*subproc_callback_t)(void *NULLABLE context, int status, const char *NULLABLE error); 91 #ifdef IOLOOP_MACOS 92 typedef bool (*ioloop_xpc_callback_t)(xpc_connection_t NULLABLE conn, xpc_object_t NULLABLE request); 93 #endif 94 95 typedef struct tls_context tls_context_t; 96 97 #define IOLOOP_SECOND 1000LL 98 #define IOLOOP_MINUTE 60 * IOLOOP_SECOND 99 #define IOLOOP_HOUR 60 * IOLOOP_MINUTE 100 #define IOLOOP_DAY 24 * IOLOOP_HOUR 101 102 struct io { 103 int ref_count; 104 io_t *NULLABLE next; 105 io_callback_t NULLABLE read_callback; 106 io_callback_t NULLABLE write_callback; 107 finalize_callback_t NULLABLE finalize; 108 void *NULLABLE context; 109 io_t *NULLABLE cancel_on_close; 110 #ifdef IOLOOP_MACOS 111 dispatch_source_t NULLABLE read_source; 112 dispatch_source_t NULLABLE write_source; 113 #else 114 bool want_read : 1; 115 bool want_write : 1; 116 #endif 117 int fd; 118 }; 119 120 struct wakeup { 121 int ref_count; 122 wakeup_t *NULLABLE next; 123 void *NULLABLE context; 124 wakeup_callback_t NULLABLE wakeup; 125 finalize_callback_t NULLABLE finalize; 126 #ifdef IOLOOP_MACOS 127 dispatch_source_t NULLABLE dispatch_source; 128 #else 129 int64_t wakeup_time; 130 #endif 131 }; 132 133 struct dso_transport { 134 int ref_count; 135 #ifdef IOLOOP_MACOS 136 nw_connection_t NULLABLE connection; 137 nw_listener_t NULLABLE listener; 138 nw_parameters_t NULLABLE parameters; 139 int writes_pending; 140 bool read_pending; // Only ever one. 141 bool server; // Indicates that this connection was created by a listener 142 bool connection_ready; 143 wakeup_t *NULLABLE idle_timer; 144 // nw_connection objects aren't necessarily ready to write to immediately. But when we create an outgoing connection, we 145 // typically want to write to it immediately. So we have a one-datum queue in case this happens; if the connection takes 146 // so long to get ready that another write happens, we drop the first write. This will work okay for UDP connections, where 147 // the retransmit logic is in the application. For future, we may want to rearchitect the flow so that the write is always 148 // done in a callback. 149 dispatch_data_t NULLABLE pending_write; 150 #else 151 io_t io; 152 #endif 153 uint16_t listen_port; 154 uint16_t *NULLABLE avoid_ports; 155 int num_avoid_ports; 156 bool avoiding; 157 char *NONNULL name; 158 void *NULLABLE context; 159 datagram_callback_t NULLABLE datagram_callback; 160 comm_callback_t NULLABLE close_callback; 161 connect_callback_t NULLABLE connected; 162 disconnect_callback_t NULLABLE disconnected; 163 finalize_callback_t NULLABLE finalize; 164 cancel_callback_t NULLABLE cancel; 165 ready_callback_t NULLABLE ready; 166 message_t *NULLABLE message; 167 uint8_t *NULLABLE buf; 168 dso_state_t *NULLABLE dso; 169 tls_context_t *NULLABLE tls_context; 170 addr_t address, multicast; 171 size_t message_length_len; 172 size_t message_length, message_cur; 173 uint8_t message_length_bytes[2]; 174 bool tcp_stream: 1; 175 bool is_multicast: 1; 176 }; 177 178 #define MAX_SUBPROC_ARGS 20 179 struct subproc { 180 int ref_count; 181 #ifdef IOLOOP_MACOS 182 dispatch_source_t NULLABLE dispatch_source; 183 #else 184 subproc_t *NULLABLE next; 185 #endif 186 int pipe_fds[2]; 187 io_t *NULLABLE output_fd; 188 void *NULLABLE context; 189 subproc_callback_t NONNULL callback; 190 finalize_callback_t NULLABLE finalize; 191 char *NULLABLE argv[MAX_SUBPROC_ARGS + 1]; 192 int argc; 193 pid_t pid; 194 }; 195 196 struct dnssd_txn { 197 int ref_count; 198 DNSServiceRef NULLABLE sdref; 199 void *NULLABLE context; 200 void *NULLABLE aux_pointer; 201 dnssd_txn_finalize_callback_t NULLABLE finalize_callback; 202 }; 203 204 extern int64_t ioloop_now; 205 int getipaddr(addr_t *NONNULL addr, const char *NONNULL p); 206 int64_t ioloop_timenow(void); 207 message_t *NULLABLE message_allocate(size_t message_size); 208 void message_free(message_t *NONNULL message); 209 void ioloop_close(io_t *NONNULL io); 210 void ioloop_add_reader(io_t *NONNULL io, io_callback_t NONNULL callback); 211 wakeup_t *NULLABLE ioloop_wakeup_create(void); 212 #define ioloop_wakeup_retain(wakeup) ioloop_wakeup_retain_(wakeup, __FILE__, __LINE__) 213 void ioloop_wakeup_retain_(wakeup_t *NONNULL wakeup, const char *NONNULL file, int line); 214 #define ioloop_wakeup_release(wakeup) ioloop_wakeup_release_(wakeup, __FILE__, __LINE__) 215 void ioloop_wakeup_release_(wakeup_t *NONNULL wakeup, const char *NONNULL file, int line); 216 bool ioloop_add_wake_event(wakeup_t *NONNULL wakeup, void *NULLABLE context, 217 wakeup_callback_t NONNULL callback, finalize_callback_t NULLABLE finalize, 218 int milliseconds); 219 void ioloop_cancel_wake_event(wakeup_t *NONNULL wakeup); 220 221 bool ioloop_init(void); 222 int ioloop(void); 223 224 #define ioloop_comm_retain(comm) ioloop_comm_retain_(comm, __FILE__, __LINE__) 225 void ioloop_comm_retain_(comm_t *NONNULL comm, const char *NONNULL file, int line); 226 #define ioloop_comm_release(wakeup) ioloop_comm_release_(wakeup, __FILE__, __LINE__) 227 void ioloop_comm_release_(comm_t *NONNULL comm, const char *NONNULL file, int line); 228 void ioloop_comm_cancel(comm_t *NONNULL comm); 229 #define ioloop_listener_retain(comm) ioloop_listener_retain_(comm, __FILE__, __LINE__) 230 void ioloop_listener_retain_(comm_t *NONNULL listener, const char *NONNULL file, int line); 231 #define ioloop_listener_release(wakeup) ioloop_listener_release_(wakeup, __FILE__, __LINE__) 232 void ioloop_listener_release_(comm_t *NONNULL listener, const char *NONNULL file, int line); 233 void ioloop_listener_cancel(comm_t *NONNULL comm); 234 comm_t *NULLABLE ioloop_listener_create(bool stream, bool tls, uint16_t *NULLABLE avoid_ports, int num_avoid_ports, 235 const addr_t *NULLABLE ip_address, const char *NULLABLE multicast, 236 const char *NONNULL name, datagram_callback_t NONNULL datagram_callback, 237 connect_callback_t NULLABLE connected, cancel_callback_t NULLABLE cancel, 238 ready_callback_t NULLABLE ready, finalize_callback_t NULLABLE finalize, 239 void *NULLABLE context); 240 comm_t *NULLABLE ioloop_connection_create(addr_t *NONNULL remote_address, bool tls, bool stream, 241 datagram_callback_t NONNULL datagram_callback, 242 connect_callback_t NULLABLE connected, 243 disconnect_callback_t NULLABLE disconnected, 244 finalize_callback_t NULLABLE finalize, 245 void *NONNULL context); 246 #define ioloop_message_retain(wakeup) ioloop_message_retain_(wakeup, __FILE__, __LINE__) 247 void ioloop_message_retain_(message_t *NONNULL message, const char *NONNULL file, int line); 248 #define ioloop_message_release(wakeup) ioloop_message_release_(wakeup, __FILE__, __LINE__) 249 void ioloop_message_release_(message_t *NONNULL message, const char *NONNULL file, int line); 250 bool ioloop_send_message(comm_t *NONNULL connection, message_t *NULLABLE responding_to, 251 struct iovec *NONNULL iov, int iov_len); 252 bool ioloop_map_interface_addresses(void *NULLABLE context, interface_callback_t NONNULL callback); 253 ssize_t ioloop_recvmsg(int sock, uint8_t *NONNULL buffer, size_t buffer_length, int *NONNULL ifindex, 254 int *NONNULL hoplimit, addr_t *NONNULL source, addr_t *NONNULL destination); 255 #define ioloop_subproc_release(subproc) ioloop_subproc_release_(subproc, __FILE__, __LINE__) 256 void ioloop_subproc_release_(subproc_t *NONNULL subproc, const char *NONNULL file, int line); 257 #define ioloop_subproc_retain(subproc) ioloop_subproc_retain_(subproc, __FILE__, __LINE__) 258 void ioloop_subproc_retain_(subproc_t *NONNULL subproc, const char *NONNULL file, int line); 259 subproc_t *NULLABLE ioloop_subproc(const char *NONNULL exepath, char *NULLABLE *NONNULL argv, int argc, 260 subproc_callback_t NULLABLE callback, io_callback_t NULLABLE output_callback, 261 void *NULLABLE context); 262 #define ioloop_dnssd_txn_add(ref, context, finalize) ioloop_dnssd_txn_add_(ref, context, finalize, __FILE__, __LINE__) 263 dnssd_txn_t *NULLABLE 264 ioloop_dnssd_txn_add_(DNSServiceRef NONNULL ref, void *NULLABLE context, 265 dnssd_txn_finalize_callback_t NULLABLE callback, const char *NONNULL file, int line); 266 void ioloop_dnssd_txn_cancel(dnssd_txn_t *NONNULL txn); 267 #define ioloop_dnssd_txn_retain(txn) ioloop_dnssd_txn_retain_(txn, __FILE__, __LINE__) 268 void ioloop_dnssd_txn_retain_(dnssd_txn_t *NONNULL txn, const char *NONNULL file, int line); 269 #define ioloop_dnssd_txn_release(txn) ioloop_dnssd_txn_release_(txn, __FILE__, __LINE__) 270 void ioloop_dnssd_txn_release_(dnssd_txn_t *NONNULL txn, const char *NONNULL file, int line); 271 #endif 272 void ioloop_dnssd_txn_set_aux_pointer(dnssd_txn_t *NONNULL txn, void *NULLABLE aux_pointer); 273 void *NULLABLE ioloop_dnssd_txn_get_aux_pointer(dnssd_txn_t *NONNULL txn); 274 void *NULLABLE ioloop_dnssd_txn_get_context(dnssd_txn_t *NONNULL txn); 275 276 #define ioloop_file_descriptor_create(fd, context, finalize) \ 277 ioloop_file_descriptor_create_(fd, context, finalize, __FILE__, __LINE__) 278 io_t *NULLABLE ioloop_file_descriptor_create_(int fd, void *NULLABLE context, finalize_callback_t NULLABLE finalize, 279 const char *NONNULL file, int line); 280 #define ioloop_file_descriptor_retain(file_descriptor) ioloop_file_descriptor_retain_(file_descriptor, __FILE__, \ 281 __LINE__) 282 void ioloop_file_descriptor_retain_(io_t *NONNULL file_descriptor, const char *NONNULL file, int line); 283 #define ioloop_file_descriptor_release(file_descriptor) ioloop_file_descriptor_release_(file_descriptor, __FILE__, \ 284 __LINE__) 285 void ioloop_file_descriptor_release_(io_t *NONNULL file_descriptor, const char *NONNULL file, int line); 286 287 bool ioloop_interface_monitor_start(void); 288 289 #ifdef IOLOOP_MACOS 290 xpc_connection_t NULLABLE ioloop_create_xpc_service(const char *NONNULL name, ioloop_xpc_callback_t NONNULL callback); 291 #endif 292 293 // Local Variables: 294 // mode: C 295 // tab-width: 4 296 // c-file-style: "bsd" 297 // c-basic-offset: 4 298 // fill-column: 108 299 // indent-tabs-mode: nil 300 // End: 301