Chromium Code Reviews| 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 |