1 #include "unittest_common.h" 2 #include "dns_sd.h" 3 #include "mDNSEmbeddedAPI.h" 4 #include "mDNSMacOSX.h" 5 6 static mDNS_PlatformSupport PlatformStorage; 7 #define RR_CACHE_SIZE ((32*1024) / sizeof(CacheRecord)) 8 static CacheEntity gRrcachestorage[RR_CACHE_SIZE]; 9 10 // Primary interface info that is used when simulating the receive of the response packet 11 mDNSInterfaceID primary_interfaceID; 12 mDNSAddr primary_v4; 13 mDNSAddr primary_v6; 14 mDNSAddr primary_router; 15 16 // This function sets up the minimum environement to run a unit test. It 17 // initializes logging, interfaces, and timenow. 18 mDNSexport mStatus init_mdns_environment(mDNSBool enableLogging) 19 { 20 mDNS *m = &mDNSStorage; 21 22 init_logging_ut(); 23 mDNS_LoggingEnabled = enableLogging; 24 mDNS_PacketLoggingEnabled = enableLogging; 25 26 mStatus result = mDNS_InitStorage_ut(m, &PlatformStorage, gRrcachestorage, RR_CACHE_SIZE, mDNSfalse, mDNSNULL, mDNSNULL); 27 if (result != mStatus_NoError) 28 return result; 29 30 primary_v4 = primary_v6 = primary_router = zeroAddr; 31 SetInterfaces_ut(&primary_interfaceID, &primary_v4, &primary_v6, &primary_router); 32 33 m->timenow = mDNS_TimeNow_NoLock(m); 34 return mStatus_NoError; 35 } 36 37 // This function sets up the minimum environement to run a unit test. It 38 // initializes logging and timenow. This is the call to use if your 39 // unit test does not use interfaces. 40 mDNSexport mStatus init_mdns_storage() 41 { 42 mDNS *m = &mDNSStorage; 43 44 init_logging_ut(); 45 mDNS_LoggingEnabled = 1; 46 mDNS_PacketLoggingEnabled = 1; 47 48 mStatus result = mDNS_InitStorage_ut(m, &PlatformStorage, gRrcachestorage, RR_CACHE_SIZE, mDNSfalse, mDNSNULL, mDNSNULL); 49 if (result != mStatus_NoError) 50 return result; 51 52 return mStatus_NoError; 53 } 54 55 mDNSlocal void init_client_request(request_state* req, char *msgbuf, size_t msgSize, uint32_t op) 56 { 57 // Simulate read_msg behavior since unit test does not open a socket 58 memset(req, 0, sizeof(request_state)); 59 60 req->ts = t_complete; 61 req->msgbuf = mDNSNULL; 62 req->msgptr = msgbuf; 63 req->msgend = msgbuf + msgSize; 64 65 // The rest of the request values are set in order to simulate a request 66 req->sd = client_req_sd; 67 req->uid = client_req_uid; 68 req->hdr_bytes = client_req_hdr_bytes; 69 req->hdr.version = client_req_hdr_version; 70 req->hdr.op = op; // query_request 71 req->hdr.datalen = msgSize; 72 req->data_bytes = msgSize; 73 req->process_id = client_req_process_id; 74 memcpy(req->pid_name, client_req_pid_name, strlen(client_req_pid_name)); 75 } 76 77 // This function calls the mDNSResponder handle_client_request() API. It initializes 78 // the request and query data structures. 79 mDNSexport mStatus start_client_request(request_state* req, char *msgbuf, size_t msgsz, uint32_t op, UDPSocket* socket) 80 { 81 // Process the unit test's client request 82 init_client_request(req, msgbuf, msgsz, op); 83 84 mStatus result = handle_client_request_ut((void*)req); 85 DNSQuestion* q = &req->u.queryrecord.q; 86 q->LocalSocket = socket; 87 return result; 88 } 89 90 // This function calls the mDNSResponder mDNSCoreReceive() API. 91 mDNSexport void receive_response(const request_state* req, DNSMessage *msg, size_t msgSize) 92 { 93 mDNS *m = &mDNSStorage; 94 mDNSAddr srcaddr; 95 mDNSIPPort srcport, dstport; 96 const mDNSu8 * end; 97 DNSQuestion *q = (DNSQuestion *)&req->u.queryrecord.q; 98 UInt8* data = (UInt8*)msg; 99 100 // Used same values for DNS server as specified during init of unit test 101 srcaddr.type = mDNSAddrType_IPv4; 102 srcaddr.ip.v4.NotAnInteger = dns_server_ipv4.NotAnInteger; 103 srcport.NotAnInteger = client_resp_src_port; 104 105 // Used random value for dstport 106 dstport.NotAnInteger = swap16((mDNSu16)client_resp_dst_port); 107 108 // Set DNS message (that was copied from a WireShark packet) 109 end = (const mDNSu8 *)msg + msgSize; 110 111 // Set socket info that mDNSCoreReceive uses to verify socket context 112 q->LocalSocket->ss.port.NotAnInteger = swap16((mDNSu16)client_resp_dst_port); 113 q->TargetQID.b[0] = data[0]; 114 q->TargetQID.b[1] = data[1]; 115 116 // Execute mDNSCoreReceive which copies two DNS records into the cache 117 mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &primary_v4, dstport, primary_interfaceID); 118 } 119 120 mDNSexport size_t get_reply_len(char* name, uint16_t rdlen) 121 { 122 size_t len = sizeof(DNSServiceFlags); 123 len += sizeof(mDNSu32); // interface index 124 len += sizeof(DNSServiceErrorType); 125 len += strlen(name) + 1; 126 len += 3 * sizeof(mDNSu16); // type, class, rdlen 127 len += rdlen; 128 len += sizeof(mDNSu32); // TTL 129 return len; 130 } 131 132 133 void free_req(request_state* req) 134 { 135 // Cleanup request's memory usage 136 while (req->replies) 137 { 138 reply_state *reply = req->replies; 139 req->replies = req->replies->next; 140 mDNSPlatformMemFree(reply); 141 } 142 req->replies = NULL; 143 mDNSPlatformMemFree(req); 144 } 145 146 // Unit test support functions follow 147 #define SA_LEN(addr) (((addr)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) 148 149 mDNSexport void get_ip(const char *const name, struct sockaddr_storage *result) 150 { 151 struct addrinfo* aiList; 152 int err = getaddrinfo(name, NULL, NULL, &aiList); 153 if (err) fprintf(stderr, "getaddrinfo error %d for %s", err, name); 154 else memcpy(result, aiList->ai_addr, SA_LEN(aiList->ai_addr)); 155 if (aiList) freeaddrinfo(aiList); 156 } 157 158