1 /* dso-transport.h 2 * 3 * Copyright (c) 2018-2021 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 */ 18 19 #ifndef __DSO_TRANSPORT_H 20 #define __DSO_TRANSPORT_H 21 22 #include "mdns_addr_tailq.h" // For mdns_addr_tailq_t. 23 24 #ifdef DSO_USES_NETWORK_FRAMEWORK 25 #include <Network/Network.h> 26 #endif 27 28 // Maximum number of IP addresses that we'll deal with as a result of looking up a name 29 // to which to connect. 30 #define MAX_DSO_CONNECT_ADDRS 16 31 32 // Threshold above which we indicate that a DSO connection isn't writable. This is advisory, 33 // but e.g. for a Discovery Relay, if the remote proxy isn't consuming what we are sending, we 34 // should start dropping packets on the floor rather than just queueing more and more packets. 35 // 60k may actually be too much. This is used when we're using NW Framework, because it doesn't 36 // allow us to use TCP_NOTSENT_LOWAT directly. 37 #define MAX_UNSENT_BYTES 60000 38 39 // Use 0 to represent an invalid ID for the object dso_connect_state_t and dso_transport_t. 40 #define DSO_CONNECT_STATE_INVALID_SERIAL 0 41 #define DSO_TRANSPORT_INVALID_SERIAL 0 42 43 struct dso_transport { 44 dso_state_t *dso; // DSO state for which this is the transport 45 struct dso_transport *next; // Transport is on list of transports. 46 void *event_context; // I/O event context 47 mDNSAddr remote_addr; // The IP address to which we have connected 48 int remote_port; // The port to which we have connected 49 50 uint32_t serial; // Serial number for locating possibly freed dso_transport_t structs. 51 #ifdef DSO_USES_NETWORK_FRAMEWORK 52 nw_connection_t connection; 53 dispatch_data_t to_write; 54 size_t bytes_to_write; 55 size_t unsent_bytes; 56 bool write_failed; // This is set if any of the parts of the dso_write process fail 57 #else 58 TCPSocket *connection; // Socket connected to Discovery Proxy 59 size_t bytes_needed; 60 size_t message_length; // Length of message we are currently accumulating, if known 61 uint8_t *inbuf; // Buffer for incoming messages. 62 size_t inbuf_size; 63 uint8_t *inbufp; // Current read pointer (may not be in inbuf) 64 bool need_length; // True if we need a 2-byte length 65 66 uint8_t lenbuf[2]; // Buffer for storing the length in a DNS TCP message 67 68 #define MAX_WRITE_HUNKS 4 // When writing a DSO message, we need this many separate hunks. 69 const uint8_t *to_write[MAX_WRITE_HUNKS]; 70 ssize_t write_lengths[MAX_WRITE_HUNKS]; 71 int num_to_write; 72 #endif // DSO_USES_NETWORK_FRAMEWORK 73 74 uint8_t *outbuf; // Output buffer for building and sending DSO messages 75 size_t outbuf_size; 76 }; 77 78 typedef struct dso_lookup dso_lookup_t; 79 struct dso_lookup { 80 dso_lookup_t *next; 81 DNSServiceRef sdref; 82 }; 83 84 typedef struct dso_connect_state dso_connect_state_t; 85 86 typedef enum { 87 // When the object is created and holds a reference to the context, the callback(see below) is called with 88 // dso_connect_life_cycle_create. 89 dso_connect_life_cycle_create, 90 // When the object is canceled, the callback(see below) is called with dso_connect_life_cycle_cancel to provide a 91 // chance for the context to do the corresponding cleaning work(cancel or release/free). 92 dso_connect_life_cycle_cancel, 93 // When the object is freed, the callback(see below) is called with dso_connect_life_cycle_free to provide a chance 94 // for the context to clean anything remains allocated. 95 dso_connect_life_cycle_free 96 } dso_connect_life_cycle_t; 97 98 typedef bool (*dso_connect_life_cycle_context_callback_t)(const dso_connect_life_cycle_t life_cycle, 99 void *const context, dso_connect_state_t *const dso_connect); 100 101 typedef struct dso_transport_address dso_transport_address_t; 102 struct dso_transport_address { 103 dso_transport_address_t *next; 104 mDNSAddr address; 105 mDNSIPPort port; 106 }; 107 108 struct dso_connect_state { 109 dso_connect_state_t *next; 110 dso_event_callback_t callback; 111 dso_state_t *dso; 112 char *detail; 113 void *context; 114 115 // The callback gets called when dso_state_t is created, canceled or finalized to do some status maintaining 116 // operation for the context. This is passed into dso_state_create(), when dso_connect_state_t uses the context to 117 // create a new dso_state_t in dso_connection_succeeded(). 118 dso_life_cycle_context_callback_t dso_context_callback; 119 // The callback gets called when dso_connect_t is created, canceled or finalized to do some status maintaining 120 // operation for the context. 121 dso_connect_life_cycle_context_callback_t dso_connect_context_callback; 122 TCPListener *listener; 123 124 uint32_t serial; // Serial number that identifies a specific dso_connect_state_t. 125 char *hostname; 126 127 // A list of addresses that we've discovered, and the next address to try. 128 dso_transport_address_t *addrs, *next_addr; 129 DNSServiceRef lookup; 130 mDNSBool canceled; // Indicates if the dso_connect_state_t has been canceled and should be ignored for processing. 131 132 mDNSBool connecting; 133 134 #if MDNSRESPONDER_SUPPORTS(APPLE, TERMINUS_ASSISTED_UNICAST_DISCOVERY) 135 // A boolean value to indicate whether the dso session should use the preconfigured TLS server certificates to 136 // perform the trust evaluation. 137 mDNSBool trusts_alternative_server_certificates; 138 #endif 139 140 mDNSIPPort config_port, connect_port; 141 dso_transport_t *transport; 142 #ifdef DSO_USES_NETWORK_FRAMEWORK 143 nw_connection_t connection; 144 bool tls_enabled; 145 #else 146 size_t inbuf_size; 147 #endif 148 size_t outbuf_size; 149 int max_outstanding_queries; 150 mDNSs32 last_event; 151 mDNSs32 reconnect_time; 152 mDNSu32 if_idx; // The index of the interface where the DSO session is established through. 153 }; 154 155 typedef struct { 156 TCPListener *listener; 157 dso_event_callback_t callback; 158 void *context; 159 } dso_listen_context_t; 160 161 typedef struct { 162 const uint8_t *message; 163 size_t length; 164 } dso_message_payload_t; 165 166 void dso_transport_init(void); 167 mStatus dso_set_connection(dso_state_t *dso, TCPSocket *socket); 168 void dso_schedule_reconnect(mDNS *m, dso_connect_state_t *cs, mDNSs32 when); 169 void dso_set_callback(dso_state_t *dso, void *context, dso_event_callback_t cb); 170 mStatus dso_message_write(dso_state_t *dso, dso_message_t *msg, bool disregard_low_water); 171 dso_connect_state_t *dso_connect_state_create( 172 const char *hostname, mDNSAddr *addr, mDNSIPPort port, 173 int max_outstanding_queries, size_t inbuf_size, size_t outbuf_size, 174 dso_event_callback_t callback, 175 dso_state_t *dso, void *context, 176 const dso_life_cycle_context_callback_t dso_context_callback, 177 const dso_connect_life_cycle_context_callback_t dso_connect_context_callback, 178 const char *detail); 179 #ifdef DSO_USES_NETWORK_FRAMEWORK 180 void dso_connect_state_use_tls(dso_connect_state_t *cs); 181 #endif 182 void dso_connect_state_cancel(dso_connect_state_t *const cs); 183 bool dso_connect(dso_connect_state_t *connect_state); 184 void dso_reconnect(dso_connect_state_t *cs, dso_state_t *dso); 185 mStatus dso_listen(dso_connect_state_t *listen_context); 186 bool dso_write_start(dso_transport_t *transport, size_t length); 187 bool dso_write_finish(dso_transport_t *transport); 188 void dso_write(dso_transport_t *transport, const uint8_t *buf, size_t length); 189 #endif // __DSO_TRANSPORT_H 190 191 // Local Variables: 192 // mode: C 193 // tab-width: 4 194 // c-file-style: "bsd" 195 // c-basic-offset: 4 196 // fill-column: 108 197 // indent-tabs-mode: nil 198 // End: 199