3 * Copyright (c) 2020 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * SRP Advertising Proxy utility program, allows:
18 * start/stop advertising proxy
19 * get/track list of service types
20 * get/track list of services of a particular type
21 * get/track list of hosts
22 * get/track information about a particular host
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
40 #include "advertising_proxy_services.h"
42 dispatch_queue_t main_queue
;
45 started_callback(advertising_proxy_conn_ref cref
, xpc_object_t response
, advertising_proxy_error_type err
)
47 INFO("started: cref %p response %p err %d.", cref
, response
, err
);
48 if (err
!= kDNSSDAdvertisingProxyStatus_NoError
) {
54 flushed_callback(advertising_proxy_conn_ref cref
, xpc_object_t response
, advertising_proxy_error_type err
)
56 INFO("flushed: cref %p response %p err %d.", cref
, response
, err
);
57 if (err
!= kDNSSDAdvertisingProxyStatus_NoError
) {
60 // We don't need to wait around after flushing.
65 block_callback(advertising_proxy_conn_ref cref
, xpc_object_t response
, advertising_proxy_error_type err
)
67 INFO("blocked: cref %p response %p err %d.", cref
, response
, err
);
68 if (err
!= kDNSSDAdvertisingProxyStatus_NoError
) {
71 // We don't need to wait around after blocking.
76 unblock_callback(advertising_proxy_conn_ref cref
, xpc_object_t response
, advertising_proxy_error_type err
)
78 INFO("unblocked: cref %p response %p err %d.", cref
, response
, err
);
79 if (err
!= kDNSSDAdvertisingProxyStatus_NoError
) {
82 // We don't need to wait around after unblocking.
87 regenerate_callback(advertising_proxy_conn_ref cref
, xpc_object_t response
, advertising_proxy_error_type err
)
89 INFO("regenerated ula: cref %p response %p err %d.", cref
, response
, err
);
90 if (err
!= kDNSSDAdvertisingProxyStatus_NoError
) {
93 // We don't need to wait around after unblocking.
98 services_callback(advertising_proxy_conn_ref cref
, xpc_object_t response
, advertising_proxy_error_type err
)
101 int64_t lease
, hours
, minutes
, seconds
;
102 INFO("services: cref %p response %p err %d.", cref
, response
, err
);
103 if (err
!= kDNSSDAdvertisingProxyStatus_NoError
) {
106 xpc_object_t services
= xpc_dictionary_get_value(response
, "instances");
107 if (services
== NULL
) {
108 INFO("Non-error response doesn't contain an instances key");
111 if (xpc_get_type(services
) != XPC_TYPE_ARRAY
) {
112 INFO("Non-error response instances value is not an array");
115 num
= xpc_array_get_count(services
);
117 INFO("No registered services.");
119 for (i
= 0; i
< num
; i
++) {
120 xpc_object_t dict
= xpc_array_get_value(services
, i
);
121 if (dict
== NULL
|| xpc_get_type(dict
) != XPC_TYPE_DICTIONARY
) {
122 INFO("services array[%d] is not a dictionary", i
);
125 const char *hostname
, *instance_name
, *service_type
, *port
, *address
, *regname
;
126 regname
= xpc_dictionary_get_string(dict
, "regname");
127 hostname
= xpc_dictionary_get_string(dict
, "hostname");
128 instance_name
= xpc_dictionary_get_string(dict
, "name");
129 if (instance_name
== NULL
) {
130 instance_name
= "<no instances>";
134 service_type
= xpc_dictionary_get_string(dict
, "type");
135 port
= xpc_dictionary_get_string(dict
, "port");
137 address
= xpc_dictionary_get_string(dict
, "address");
138 lease
= xpc_dictionary_get_int64(dict
, "lease");
139 hours
= lease
/ 3600 / 1000;
140 lease
-= hours
* 3600 * 1000;
141 minutes
= lease
/ 60 / 1000;
142 lease
-= minutes
* 60 * 1000;
143 seconds
= lease
/ 1000;
144 lease
-= seconds
* 1000;
146 printf("\"%s\" \"%s\" %s %s %s %qd:%qd:%qd.%qd \"%s\"\n", regname
, instance_name
, service_type
, port
,
147 address
== NULL
? "" : address
, hours
, minutes
, seconds
, lease
, hostname
);
155 ERROR("srputil start -- start the SRP MDNS Proxy through launchd");
156 ERROR(" services -- get the list of services currently being advertised");
157 ERROR(" block -- block the SRP listener");
158 ERROR(" unblock -- unblock the SRP listener");
159 ERROR(" regenerate-ula -- generate a new ULA and restart the network");
161 ERROR(" flush -- flush all entries from the SRP proxy (for testing only)");
166 main(int argc
, char **argv
)
169 bool start_proxy
= false;
170 bool flush_entries
= false;
171 bool list_services
= false;
173 bool unblock
= false;
174 bool regenerate_ula
= false;
180 for (i
= 1; i
< argc
; i
++) {
181 if (!strcmp(argv
[i
], "start")) {
183 } else if (!strcmp(argv
[i
], "flush")) {
184 flush_entries
= true;
185 } else if (!strcmp(argv
[i
], "services")) {
186 list_services
= true;
187 } else if (!strcmp(argv
[i
], "block")) {
189 } else if (!strcmp(argv
[i
], "unblock")) {
191 } else if (!strcmp(argv
[i
], "regenerate-ula")) {
192 regenerate_ula
= true;
194 } else if (!strcmp(argv
[i
], "watch")) {
195 ERROR("Watching not implemented yet.");
197 } else if (!strcmp(argv
[i
], "get")) {
198 ERROR("Getting not implemented yet.");
206 main_queue
= dispatch_get_main_queue();
207 dispatch_retain(main_queue
);
209 // Start the queue, //then// do the work
210 dispatch_async(main_queue
, ^{
211 advertising_proxy_error_type err
= kDNSSDAdvertisingProxyStatus_NoError
;;
212 advertising_proxy_conn_ref cref
= NULL
;
215 err
= advertising_proxy_enable(&cref
, main_queue
, started_callback
);
217 if (err
== kDNSSDAdvertisingProxyStatus_NoError
&& flush_entries
) {
218 err
= advertising_proxy_flush_entries(&cref
, main_queue
, flushed_callback
);
220 if (err
== kDNSSDAdvertisingProxyStatus_NoError
&& list_services
) {
221 err
= advertising_proxy_get_service_list(&cref
, main_queue
, services_callback
);
223 if (err
== kDNSSDAdvertisingProxyStatus_NoError
&& block
) {
224 err
= advertising_proxy_block_service(&cref
, main_queue
, block_callback
);
226 if (err
== kDNSSDAdvertisingProxyStatus_NoError
&& unblock
) {
227 err
= advertising_proxy_unblock_service(&cref
, main_queue
, unblock_callback
);
229 if (err
== kDNSSDAdvertisingProxyStatus_NoError
&& regenerate_ula
) {
230 err
= advertising_proxy_regenerate_ula(&cref
, main_queue
, regenerate_callback
);
232 if (err
!= kDNSSDAdvertisingProxyStatus_NoError
) {
242 // c-file-style: "bsd"
245 // indent-tabs-mode: nil