OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE.md file. |
| 4 |
| 5 #if defined(FLETCH_TARGET_OS_MACOS) |
| 6 |
| 7 #include <errno.h> |
| 8 #include <stdio.h> |
| 9 #include <stdlib.h> |
| 10 #include <string.h> |
| 11 #include <arpa/inet.h> |
| 12 #include <pthread.h> |
| 13 |
| 14 #include <dns_sd.h> |
| 15 |
| 16 #include "include/dart_api.h" |
| 17 #include "include/dart_native_api.h" |
| 18 |
| 19 #include "mdns_extension.h" |
| 20 |
| 21 // Context passed to the callback receiving the mDNS information. |
| 22 struct Context { |
| 23 // The Dart port where the result should be delivered. |
| 24 Dart_Port port; |
| 25 }; |
| 26 |
| 27 // Print fatal error and exit. |
| 28 static void Fatal(const char *message) { |
| 29 fprintf(stderr, "%s (errno %d)\n", message, errno); |
| 30 exit(-1); |
| 31 } |
| 32 |
| 33 // Code running in the threads started for pumping the results. |
| 34 static void* ThreadFunction(void* data) { |
| 35 DNSServiceRef ref = reinterpret_cast<DNSServiceRef>(data); |
| 36 |
| 37 // Preocess results until an error occurs. |
| 38 DNSServiceErrorType result = kDNSServiceErr_NoError; |
| 39 while (result == kDNSServiceErr_NoError) { |
| 40 result = DNSServiceProcessResult(ref); |
| 41 } |
| 42 // The expected error from deallocation the ref. |
| 43 if (result != kDNSServiceErr_BadReference) { |
| 44 fprintf(stderr, "Error from DNSServiceProcessResult: %d\n", result); |
| 45 } |
| 46 |
| 47 return NULL; |
| 48 } |
| 49 |
| 50 // Start a thread for receiving results from a specific DNSServiceRef. |
| 51 static int StartThread(DNSServiceRef ref) { |
| 52 pthread_attr_t attr; |
| 53 int result = pthread_attr_init(&attr); |
| 54 if (result != 0) Fatal("Error from pthread_attr_init"); |
| 55 |
| 56 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
| 57 if (result != 0) Fatal("Error from pthread_attr_setdetachstate"); |
| 58 |
| 59 pthread_t tid; |
| 60 result = pthread_create(&tid, &attr, ThreadFunction, ref); |
| 61 if (result != 0) Fatal("Error from pthread_create"); |
| 62 |
| 63 result = pthread_attr_destroy(&attr); |
| 64 if (result != 0) Fatal("Error from pthread_attr_destroy"); |
| 65 |
| 66 return 0; |
| 67 } |
| 68 |
| 69 // Callback for results initiated by calling DNSServiceGetAddrInfo. |
| 70 static void GetAddrInfoCallback(DNSServiceRef ref, |
| 71 DNSServiceFlags flags, |
| 72 uint32_t interfaceIndex, |
| 73 DNSServiceErrorType errorCode, |
| 74 const char *hostname, |
| 75 const struct sockaddr *address, |
| 76 uint32_t ttl, |
| 77 void *context) { |
| 78 if (address->sa_family == AF_INET) { |
| 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 |
| 83 struct Context* ctx = reinterpret_cast<struct Context*>(context); |
| 84 |
| 85 // Build the response message. |
| 86 Dart_CObject cobject_hostname; |
| 87 cobject_hostname.type = Dart_CObject_kString; |
| 88 cobject_hostname.value.as_string = const_cast<char*>(hostname); |
| 89 Dart_CObject cobject_address; |
| 90 cobject_address.type = Dart_CObject_kTypedData; |
| 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 |
| 101 // Result received, free allocated data and stop lookup. |
| 102 free(ctx); |
| 103 DNSServiceRefDeallocate(ref); |
| 104 } |
| 105 } |
| 106 |
| 107 // Lookup request from Dart. |
| 108 void HandleLookup(Dart_Port port_id, char* hostname) { |
| 109 DNSServiceRef ref; |
| 110 DNSServiceErrorType result; |
| 111 struct Context* context = |
| 112 reinterpret_cast<struct Context*>(malloc(sizeof(struct Context))); |
| 113 context->port = port_id; |
| 114 result = DNSServiceGetAddrInfo(&ref, |
| 115 0, |
| 116 0, |
| 117 kDNSServiceProtocol_IPv4, |
| 118 hostname, |
| 119 &GetAddrInfoCallback, |
| 120 context); |
| 121 if (result != kDNSServiceErr_NoError) { |
| 122 fprintf(stderr, "Error from DNSServiceProcessResult: %d\n", result); |
| 123 } else { |
| 124 // Start a thread for retreiving the results. |
| 125 // TODO(sgjesse): Add a timeout for killing the thread if there |
| 126 // are no responses. |
| 127 StartThread(ref); |
| 128 } |
| 129 } |
| 130 |
| 131 #endif |
OLD | NEW |