Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(786)

Side by Side Diff: src/pkg/mdns/mdns_extension_macos.cc

Issue 1416833009: Add multiple results and timeout handling to the Mac OS mDNS native extension (Closed) Base URL: git@github.com:dart-lang/fletch.git@master
Patch Set: Addressed review comments and added new SHA1 for native extension Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 = DNSServiceProcessResult(ctx->ref);
88 if (result != kDNSServiceErr_NoError) break;
89
90 // Prepare new timeout.
91 if (gettimeofday(&time, NULL) == -1) break;
45 } 92 }
46 93
94 FreeContext(ctx);
47 return NULL; 95 return NULL;
48 } 96 }
49 97
50 // Start a thread for receiving results from a specific DNSServiceRef. 98 // Start a thread for receiving results from a specific DNSServiceRef.
51 static int StartThread(DNSServiceRef ref) { 99 static int StartThread(Context* ctx) {
52 pthread_attr_t attr; 100 pthread_attr_t attr;
53 int result = pthread_attr_init(&attr); 101 int result = pthread_attr_init(&attr);
54 if (result != 0) Fatal("Error from pthread_attr_init"); 102 if (result != 0) Fatal("Error from pthread_attr_init");
55 103
56 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 104 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
57 if (result != 0) Fatal("Error from pthread_attr_setdetachstate"); 105 if (result != 0) Fatal("Error from pthread_attr_setdetachstate");
58 106
59 pthread_t tid; 107 pthread_t tid;
60 result = pthread_create(&tid, &attr, ThreadFunction, ref); 108 result = pthread_create(&tid, &attr, ThreadFunction, ctx);
61 if (result != 0) Fatal("Error from pthread_create"); 109 if (result != 0) Fatal("Error from pthread_create");
62 110
63 result = pthread_attr_destroy(&attr); 111 result = pthread_attr_destroy(&attr);
64 if (result != 0) Fatal("Error from pthread_attr_destroy"); 112 if (result != 0) Fatal("Error from pthread_attr_destroy");
65 113
66 return 0; 114 return 0;
67 } 115 }
68 116
69 // Callback for results initiated by calling DNSServiceGetAddrInfo. 117
70 static void GetAddrInfoCallback(DNSServiceRef ref, 118 // Callback for results initiated by calling DNSServiceQueryRecord.
119 static void QueryRecordCallback(DNSServiceRef ref,
71 DNSServiceFlags flags, 120 DNSServiceFlags flags,
72 uint32_t interfaceIndex, 121 uint32_t interfaceIndex,
73 DNSServiceErrorType errorCode, 122 DNSServiceErrorType errorCode,
74 const char *hostname, 123 const char *fullname,
75 const struct sockaddr *address, 124 uint16_t rrtype,
125 uint16_t rrclass,
126 uint16_t rdlen,
127 const void* rdata,
76 uint32_t ttl, 128 uint32_t ttl,
77 void *context) { 129 void *context) {
78 if (address->sa_family == AF_INET) { 130 if (rrclass != kDNSServiceClass_IN) return;
79 const struct sockaddr_in* address_in = (const struct sockaddr_in*)address;
80 const uint8_t* addr =
81 reinterpret_cast<const uint8_t*>(&address_in->sin_addr.s_addr);
82 131
83 struct Context* ctx = reinterpret_cast<struct Context*>(context); 132 struct Context* ctx = reinterpret_cast<struct Context*>(context);
84 133
85 // Build the response message. 134 if (rrtype != kDNSServiceType_A &&
86 Dart_CObject cobject_hostname; 135 rrtype != kDNSServiceType_SRV &&
87 cobject_hostname.type = Dart_CObject_kString; 136 rrtype != kDNSServiceType_PTR) {
88 cobject_hostname.value.as_string = const_cast<char*>(hostname); 137 // Ignore unsupported types.
89 Dart_CObject cobject_address; 138 return;
90 cobject_address.type = Dart_CObject_kTypedData; 139 }
91 cobject_address.value.as_typed_data.length = 4;
92 cobject_address.value.as_typed_data.type = Dart_TypedData_kUint8;
93 cobject_address.value.as_typed_data.values = const_cast<uint8_t*>(addr);
94 Dart_CObject cobject_result;
95 cobject_result.type = Dart_CObject_kArray;
96 Dart_CObject* result_array[] = {&cobject_hostname, &cobject_address};
97 cobject_result.value.as_array.length = 2;
98 cobject_result.value.as_array.values = result_array;
99 Dart_PostCObject(ctx->port, &cobject_result);
100 140
101 // Result received, free allocated data and stop lookup. 141 // Build the response message.
102 free(ctx); 142 Dart_CObject cobject_fullname;
103 DNSServiceRefDeallocate(ref); 143 cobject_fullname.type = Dart_CObject_kString;
104 } 144 cobject_fullname.value.as_string = const_cast<char*>(fullname);
145 Dart_CObject cobject_type;
146 cobject_type.type = Dart_CObject_kInt32;
147 cobject_type.value.as_int32 = rrtype;
148 Dart_CObject cobject_ttl;
149 cobject_ttl.type = Dart_CObject_kInt32;
150 cobject_ttl.value.as_int32 = ttl;
151 Dart_CObject cobject_data;
152 cobject_data.type = Dart_CObject_kTypedData;
153 cobject_data.value.as_typed_data.length = rdlen;
154 cobject_data.value.as_typed_data.type = Dart_TypedData_kUint8;
155 cobject_data.value.as_typed_data.values =
156 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(rdata));
157 Dart_CObject cobject_result;
158 cobject_result.type = Dart_CObject_kArray;
159 Dart_CObject* result_array[] =
160 {&cobject_fullname, &cobject_type, &cobject_ttl, &cobject_data};
161 cobject_result.value.as_array.length = 4;
162 cobject_result.value.as_array.values = result_array;
163 Dart_PostCObject(ctx->port, &cobject_result);
105 } 164 }
106 165
107 // Lookup request from Dart. 166 // Lookup request from Dart.
108 void HandleLookup(Dart_Port port_id, char* hostname) { 167 void HandleLookup(Dart_Port port_id, int type, char* fullname, int timeout) {
109 DNSServiceRef ref; 168 DNSServiceRef ref;
110 DNSServiceErrorType result; 169 DNSServiceErrorType result;
111 struct Context* context = 170 struct Context* context =
112 reinterpret_cast<struct Context*>(malloc(sizeof(struct Context))); 171 reinterpret_cast<struct Context*>(malloc(sizeof(struct Context)));
113 context->port = port_id; 172 result = DNSServiceQueryRecord(&ref,
114 result = DNSServiceGetAddrInfo(&ref,
115 0, 173 0,
116 0, 174 0,
117 kDNSServiceProtocol_IPv4, 175 fullname,
118 hostname, 176 type,
119 &GetAddrInfoCallback, 177 kDNSServiceClass_IN,
178 &QueryRecordCallback,
120 context); 179 context);
121 if (result != kDNSServiceErr_NoError) { 180 if (result != kDNSServiceErr_NoError) {
122 fprintf(stderr, "Error from DNSServiceProcessResult: %d\n", result); 181 fprintf(stderr, "Error from DNSServiceQueryRecord: %d\n", result);
123 } else { 182 } else {
124 // Start a thread for retreiving the results. 183 // Start a thread for pumping the results.
125 // TODO(sgjesse): Add a timeout for killing the thread if there 184 context->ref = ref;
126 // are no responses. 185 context->timeout = timeout;
127 StartThread(ref); 186 context->port = port_id;
187 StartThread(context);
128 } 188 }
129 } 189 }
130 190
131 #endif 191 #endif
OLDNEW
« pkg/mdns/test/decode_test.dart ('K') | « src/pkg/mdns/mdns_extension_linux.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698