OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
4 | 4 |
5 #if defined(FLETCH_TARGET_OS_MACOS) | 5 #if defined(FLETCH_TARGET_OS_MACOS) |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <stdio.h> | 8 #include <stdio.h> |
9 #include <stdlib.h> | 9 #include <stdlib.h> |
10 #include <string.h> | 10 #include <string.h> |
11 #include <arpa/inet.h> | 11 #include <arpa/inet.h> |
12 #include <pthread.h> | 12 #include <pthread.h> |
13 #include <sys/time.h> | |
13 | 14 |
14 #include <dns_sd.h> | 15 #include <dns_sd.h> |
15 | 16 |
16 #include "include/dart_api.h" | 17 #include "include/dart_api.h" |
17 #include "include/dart_native_api.h" | 18 #include "include/dart_native_api.h" |
18 | 19 |
19 #include "mdns_extension.h" | 20 #include "mdns_extension.h" |
20 | 21 |
22 // Constants. | |
23 static uint32_t kUsecsInSecs = 1000000; | |
24 static uint32_t kMillisecsInUsecs = 1000; | |
25 | |
21 // Context passed to the callback receiving the mDNS information. | 26 // Context passed to the callback receiving the mDNS information. |
22 struct Context { | 27 struct Context { |
28 DNSServiceRef ref; | |
29 // The timeout waiting for results. | |
30 int timeout; | |
23 // The Dart port where the result should be delivered. | 31 // The Dart port where the result should be delivered. |
24 Dart_Port port; | 32 Dart_Port port; |
25 }; | 33 }; |
26 | 34 |
27 // Print fatal error and exit. | 35 // Print fatal error and exit. |
28 static void Fatal(const char *message) { | 36 static void Fatal(const char *message) { |
29 fprintf(stderr, "%s (errno %d)\n", message, errno); | 37 fprintf(stderr, "%s (errno %d)\n", message, errno); |
30 exit(-1); | 38 exit(-1); |
31 } | 39 } |
32 | 40 |
41 int64_t timeval_to_usec(const struct timeval* tv) { | |
42 return( (int64_t)tv->tv_sec * kUsecsInSecs + tv->tv_usec ) ; | |
43 } | |
44 | |
45 struct timeval* usec_to_timeval(int64_t usec, struct timeval* tv) { | |
46 tv->tv_sec = usec / kUsecsInSecs; | |
47 tv->tv_usec = usec % kUsecsInSecs; | |
48 return tv; | |
49 } | |
50 | |
51 // Free allocated resources associated with a context. | |
52 static void FreeContext(Context* ctx) { | |
53 DNSServiceRefDeallocate(ctx->ref); | |
54 free(ctx); | |
55 } | |
56 | |
33 // Code running in the threads started for pumping the results. | 57 // Code running in the threads started for pumping the results. |
34 static void* ThreadFunction(void* data) { | 58 static void* ThreadFunction(void* data) { |
35 DNSServiceRef ref = reinterpret_cast<DNSServiceRef>(data); | 59 Context* ctx = reinterpret_cast<Context*>(data); |
36 | 60 |
37 // Preocess results until an error occurs. | 61 // Determint the end-time for responses to this request. Timeout from Dart |
38 DNSServiceErrorType result = kDNSServiceErr_NoError; | 62 // is in milliseconds. |
39 while (result == kDNSServiceErr_NoError) { | 63 struct timeval time; |
40 result = DNSServiceProcessResult(ref); | 64 if (gettimeofday(&time, NULL) == -1) { |
65 FreeContext(ctx); | |
66 return NULL; | |
41 } | 67 } |
42 // The expected error from deallocation the ref. | 68 int64_t end_time = timeval_to_usec(&time) + ctx->timeout * kMillisecsInUsecs; |
43 if (result != kDNSServiceErr_BadReference) { | 69 |
44 fprintf(stderr, "Error from DNSServiceProcessResult: %d\n", result); | 70 // Setup single file descriptor for select. |
71 int fd = DNSServiceRefSockFD(ctx->ref); | |
72 fd_set readfds; | |
73 FD_ZERO(&readfds); | |
74 FD_SET(fd, &readfds); | |
75 while (true) { | |
76 struct timeval timeout; | |
77 int64_t timeout_usec = end_time - timeval_to_usec(&time); | |
78 if (timeout_usec <= 0) break; | |
79 usec_to_timeval(timeout_usec, &timeout); | |
80 int rc = select(fd + 1, &readfds, NULL, NULL, &timeout); | |
81 if (rc == -1 && errno == EINTR) continue; | |
82 | |
83 // Terminate the loop if timeout or error. | |
84 if (rc <= 0) break; | |
85 | |
86 // Process the result which is ready. | |
87 DNSServiceErrorType result = kDNSServiceErr_NoError; | |
88 result = DNSServiceProcessResult(ctx->ref); | |
wibling
2015/11/10 14:44:56
NIT: Merge the two above lines into one.
Søren Gjesse
2015/11/10 15:30:05
Done.
| |
89 if (result != kDNSServiceErr_NoError) break; | |
90 | |
91 // Prepare new timeout. | |
92 if (gettimeofday(&time, NULL) == -1) break; | |
45 } | 93 } |
46 | 94 |
95 FreeContext(ctx); | |
47 return NULL; | 96 return NULL; |
48 } | 97 } |
49 | 98 |
50 // Start a thread for receiving results from a specific DNSServiceRef. | 99 // Start a thread for receiving results from a specific DNSServiceRef. |
51 static int StartThread(DNSServiceRef ref) { | 100 static int StartThread(Context* ctx) { |
52 pthread_attr_t attr; | 101 pthread_attr_t attr; |
53 int result = pthread_attr_init(&attr); | 102 int result = pthread_attr_init(&attr); |
54 if (result != 0) Fatal("Error from pthread_attr_init"); | 103 if (result != 0) Fatal("Error from pthread_attr_init"); |
55 | 104 |
56 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | 105 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
57 if (result != 0) Fatal("Error from pthread_attr_setdetachstate"); | 106 if (result != 0) Fatal("Error from pthread_attr_setdetachstate"); |
58 | 107 |
59 pthread_t tid; | 108 pthread_t tid; |
60 result = pthread_create(&tid, &attr, ThreadFunction, ref); | 109 result = pthread_create(&tid, &attr, ThreadFunction, ctx); |
61 if (result != 0) Fatal("Error from pthread_create"); | 110 if (result != 0) Fatal("Error from pthread_create"); |
62 | 111 |
63 result = pthread_attr_destroy(&attr); | 112 result = pthread_attr_destroy(&attr); |
64 if (result != 0) Fatal("Error from pthread_attr_destroy"); | 113 if (result != 0) Fatal("Error from pthread_attr_destroy"); |
65 | 114 |
66 return 0; | 115 return 0; |
67 } | 116 } |
68 | 117 |
69 | 118 |
70 // Callback for results initiated by calling DNSServiceQueryRecord. | 119 // Callback for results initiated by calling DNSServiceQueryRecord. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
106 cobject_data.value.as_typed_data.type = Dart_TypedData_kUint8; | 155 cobject_data.value.as_typed_data.type = Dart_TypedData_kUint8; |
107 cobject_data.value.as_typed_data.values = | 156 cobject_data.value.as_typed_data.values = |
108 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(rdata)); | 157 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(rdata)); |
109 Dart_CObject cobject_result; | 158 Dart_CObject cobject_result; |
110 cobject_result.type = Dart_CObject_kArray; | 159 cobject_result.type = Dart_CObject_kArray; |
111 Dart_CObject* result_array[] = | 160 Dart_CObject* result_array[] = |
112 {&cobject_fullname, &cobject_type, &cobject_ttl, &cobject_data}; | 161 {&cobject_fullname, &cobject_type, &cobject_ttl, &cobject_data}; |
113 cobject_result.value.as_array.length = 4; | 162 cobject_result.value.as_array.length = 4; |
114 cobject_result.value.as_array.values = result_array; | 163 cobject_result.value.as_array.values = result_array; |
115 Dart_PostCObject(ctx->port, &cobject_result); | 164 Dart_PostCObject(ctx->port, &cobject_result); |
116 | |
117 // Result received, free allocated data and stop lookup. | |
118 free(ctx); | |
119 DNSServiceRefDeallocate(ref); | |
120 } | 165 } |
121 | 166 |
122 // Lookup request from Dart. | 167 // Lookup request from Dart. |
123 void HandleLookup(Dart_Port port_id, int type, char* fullname) { | 168 void HandleLookup(Dart_Port port_id, int type, char* fullname, int timeout) { |
124 DNSServiceRef ref; | 169 DNSServiceRef ref; |
125 DNSServiceErrorType result; | 170 DNSServiceErrorType result; |
126 struct Context* context = | 171 struct Context* context = |
127 reinterpret_cast<struct Context*>(malloc(sizeof(struct Context))); | 172 reinterpret_cast<struct Context*>(malloc(sizeof(struct Context))); |
128 context->port = port_id; | |
129 result = DNSServiceQueryRecord(&ref, | 173 result = DNSServiceQueryRecord(&ref, |
130 0, | 174 0, |
131 0, | 175 0, |
132 fullname, | 176 fullname, |
133 type, | 177 type, |
134 kDNSServiceClass_IN, | 178 kDNSServiceClass_IN, |
135 &QueryRecordCallback, | 179 &QueryRecordCallback, |
136 context); | 180 context); |
137 if (result != kDNSServiceErr_NoError) { | 181 if (result != kDNSServiceErr_NoError) { |
138 fprintf(stderr, "Error from DNSServiceQueryRecord: %d\n", result); | 182 fprintf(stderr, "Error from DNSServiceQueryRecord: %d\n", result); |
139 } else { | 183 } else { |
140 // Start a thread for retreiving the results. | 184 // Start a thread for pumping the results. |
141 // TODO(sgjesse): Add a timeout for killing the thread if there | 185 context->ref = ref; |
142 // are no responses. | 186 context->timeout = timeout; |
143 StartThread(ref); | 187 context->port = port_id; |
188 StartThread(context); | |
144 } | 189 } |
145 } | 190 } |
146 | 191 |
147 #endif | 192 #endif |
OLD | NEW |