[3951c97] | 1 | /* |
---|
| 2 | * Copyright (c) 2014 embedded brains GmbH. All rights reserved. |
---|
| 3 | * |
---|
| 4 | * embedded brains GmbH |
---|
| 5 | * Dornierstr. 4 |
---|
| 6 | * 82178 Puchheim |
---|
| 7 | * Germany |
---|
| 8 | * <rtems@embedded-brains.de> |
---|
| 9 | * |
---|
| 10 | * Redistribution and use in source and binary forms, with or without |
---|
| 11 | * modification, are permitted provided that the following conditions |
---|
| 12 | * are met: |
---|
| 13 | * 1. Redistributions of source code must retain the above copyright |
---|
| 14 | * notice, this list of conditions and the following disclaimer. |
---|
| 15 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
| 16 | * notice, this list of conditions and the following disclaimer in the |
---|
| 17 | * documentation and/or other materials provided with the distribution. |
---|
| 18 | * |
---|
| 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
---|
| 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
| 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
---|
| 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
| 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
| 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
| 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
| 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
| 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
| 29 | * SUCH DAMAGE. |
---|
| 30 | */ |
---|
| 31 | |
---|
| 32 | #include <mDNSEmbeddedAPI.h> |
---|
| 33 | #include <mDNSPosix.h> |
---|
| 34 | |
---|
| 35 | #include <sys/select.h> |
---|
| 36 | #include <sys/socket.h> |
---|
| 37 | |
---|
| 38 | #include <netinet/in.h> |
---|
| 39 | |
---|
| 40 | #include <assert.h> |
---|
| 41 | #include <errno.h> |
---|
| 42 | #include <netdb.h> |
---|
| 43 | #include <stdbool.h> |
---|
| 44 | #include <stdio.h> |
---|
| 45 | #include <stdlib.h> |
---|
| 46 | #include <string.h> |
---|
| 47 | #include <unistd.h> |
---|
| 48 | |
---|
| 49 | #define TEST_NAME "LIBBSD FOOBAR CLIENT" |
---|
| 50 | |
---|
| 51 | static mDNS mDNSStorage; |
---|
| 52 | |
---|
| 53 | static mDNS_PlatformSupport PlatformStorage; |
---|
| 54 | |
---|
| 55 | static CacheEntity rr_cache[64]; |
---|
| 56 | |
---|
| 57 | static const char * const qc_results[] = { |
---|
| 58 | "rmv", |
---|
| 59 | "add", |
---|
| 60 | "addnocache", |
---|
| 61 | "forceresponse", |
---|
| 62 | "dnssec", |
---|
| 63 | "nodnssec", |
---|
| 64 | "suppressed" |
---|
| 65 | }; |
---|
| 66 | |
---|
| 67 | typedef struct service_info_query { |
---|
| 68 | struct service_info_query *next; |
---|
| 69 | ServiceInfoQuery query; |
---|
| 70 | ServiceInfo info; |
---|
| 71 | } service_info_query; |
---|
| 72 | |
---|
| 73 | static service_info_query *service_info_query_list; |
---|
| 74 | |
---|
| 75 | static mDNSBool |
---|
| 76 | eval_service_name(const domainname *fqdn, domainlabel *name) |
---|
| 77 | { |
---|
| 78 | domainname type; |
---|
| 79 | domainname domain; |
---|
| 80 | mDNSBool ok = DeconstructServiceName(fqdn, name, &type, &domain); |
---|
| 81 | |
---|
| 82 | if (ok) { |
---|
| 83 | char name_str[MAX_DOMAIN_LABEL + 1]; |
---|
| 84 | char type_str[MAX_ESCAPED_DOMAIN_NAME]; |
---|
| 85 | char domain_str[MAX_ESCAPED_DOMAIN_NAME]; |
---|
| 86 | |
---|
| 87 | ConvertDomainLabelToCString_unescaped(name, name_str); |
---|
| 88 | ConvertDomainNameToCString(&type, type_str); |
---|
| 89 | ConvertDomainNameToCString(&domain, domain_str); |
---|
| 90 | |
---|
| 91 | printf("name = '%s', type = '%s', domain = '%s'", |
---|
| 92 | name_str, type_str, domain_str); |
---|
| 93 | } else { |
---|
| 94 | printf("?"); |
---|
| 95 | } |
---|
| 96 | |
---|
| 97 | return ok; |
---|
| 98 | } |
---|
| 99 | |
---|
| 100 | static void |
---|
| 101 | foobar_action(const struct sockaddr_storage *addr) |
---|
| 102 | { |
---|
| 103 | static const char foobar[] = "FooBar!"; |
---|
| 104 | |
---|
| 105 | int sd; |
---|
| 106 | int rv; |
---|
| 107 | |
---|
| 108 | sd = socket(addr->ss_family, SOCK_STREAM, 0); |
---|
| 109 | assert(sd >= 0); |
---|
| 110 | |
---|
| 111 | rv = connect(sd, (struct sockaddr *) addr, addr->ss_len); |
---|
| 112 | if (rv == 0) { |
---|
| 113 | char buf[sizeof(foobar)]; |
---|
| 114 | ssize_t n; |
---|
| 115 | |
---|
| 116 | n = read(sd, &buf[0], sizeof(buf)); |
---|
| 117 | if (n == (ssize_t) sizeof(buf)) { |
---|
| 118 | assert(memcmp(&buf[0], &foobar[0], sizeof(buf)) == 0); |
---|
| 119 | printf("foobar client: read: %s\n", &buf[0]); |
---|
| 120 | } else if (n >= 0) { |
---|
| 121 | printf("foobar client: partial read: %zi\n", n); |
---|
| 122 | } else { |
---|
| 123 | printf("foobar client: read error: %s\n", |
---|
| 124 | strerror(errno)); |
---|
| 125 | } |
---|
| 126 | } else { |
---|
| 127 | printf("foobar client: connect error: %s\n", strerror(errno)); |
---|
| 128 | } |
---|
| 129 | |
---|
| 130 | rv = close(sd); |
---|
| 131 | assert(rv == 0); |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | static void |
---|
| 135 | foobar_service_info(mDNS *const m, ServiceInfoQuery *query) |
---|
| 136 | { |
---|
| 137 | const ServiceInfo *i = query->info; |
---|
| 138 | struct sockaddr_storage addr; |
---|
| 139 | char host[NI_MAXHOST]; |
---|
| 140 | domainlabel name; |
---|
| 141 | int rv; |
---|
| 142 | |
---|
| 143 | memset(&addr, 0, sizeof(addr)); |
---|
| 144 | |
---|
| 145 | if (i->ip.type == mDNSAddrType_IPv4) { |
---|
| 146 | struct sockaddr_in *s = (struct sockaddr_in *) &addr; |
---|
| 147 | |
---|
| 148 | s->sin_len = sizeof(*s); |
---|
| 149 | s->sin_family = AF_INET; |
---|
| 150 | s->sin_port = i->port.NotAnInteger; |
---|
| 151 | s->sin_addr.s_addr = i->ip.ip.v4.NotAnInteger; |
---|
| 152 | } else { |
---|
| 153 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &addr; |
---|
| 154 | |
---|
| 155 | sin6->sin6_len = sizeof(*sin6); |
---|
| 156 | sin6->sin6_family = AF_INET6; |
---|
| 157 | sin6->sin6_port = i->port.NotAnInteger; |
---|
| 158 | sin6->sin6_addr = *(struct in6_addr *) &i->ip.ip.v6; |
---|
| 159 | } |
---|
| 160 | |
---|
| 161 | rv = getnameinfo((struct sockaddr *) &addr, addr.ss_len, host, |
---|
| 162 | sizeof(host), NULL, 0, NI_NUMERICHOST); |
---|
| 163 | assert(rv == 0); |
---|
| 164 | |
---|
| 165 | printf("foobar client: service info: "); |
---|
| 166 | eval_service_name(&i->name, &name); |
---|
| 167 | printf(", addr = %s, port = %i\n", &host[0], mDNSVal16(i->port)); |
---|
| 168 | |
---|
| 169 | foobar_action(&addr); |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | static void |
---|
| 173 | foobar_manage_service(mDNS *m, const ResourceRecord *answer, |
---|
| 174 | const domainlabel *name, bool add) |
---|
| 175 | { |
---|
| 176 | if (add) { |
---|
| 177 | mStatus status; |
---|
| 178 | service_info_query *siq = |
---|
| 179 | calloc(1, sizeof(*siq)); |
---|
| 180 | |
---|
| 181 | assert(siq != NULL); |
---|
| 182 | |
---|
| 183 | siq->next = service_info_query_list; |
---|
| 184 | service_info_query_list = siq; |
---|
| 185 | |
---|
| 186 | siq->info.name = answer->rdata->u.name; |
---|
| 187 | siq->info.InterfaceID = answer->InterfaceID; |
---|
| 188 | |
---|
| 189 | status = mDNS_StartResolveService(m, &siq->query, &siq->info, |
---|
| 190 | foobar_service_info, NULL); |
---|
| 191 | assert(status == mStatus_NoError); |
---|
| 192 | } else { |
---|
| 193 | service_info_query *cur = service_info_query_list; |
---|
| 194 | service_info_query *prev = cur; |
---|
| 195 | |
---|
| 196 | while (cur != NULL && !SameDomainLabel(&name->c[0], |
---|
| 197 | &cur->info.name.c[0])) { |
---|
| 198 | prev = cur; |
---|
| 199 | cur = cur->next; |
---|
| 200 | } |
---|
| 201 | |
---|
| 202 | if (cur != NULL) { |
---|
| 203 | if (prev != cur) { |
---|
| 204 | prev->next = cur->next; |
---|
| 205 | } else { |
---|
| 206 | service_info_query_list = cur->next; |
---|
| 207 | } |
---|
| 208 | |
---|
| 209 | mDNS_StopResolveService(m, &cur->query); |
---|
| 210 | free(cur); |
---|
| 211 | } |
---|
| 212 | } |
---|
| 213 | } |
---|
| 214 | |
---|
| 215 | static void |
---|
| 216 | foobar_browse(mDNS *m, DNSQuestion *question, |
---|
| 217 | const ResourceRecord *answer, QC_result res) |
---|
| 218 | { |
---|
| 219 | (void) question; |
---|
| 220 | |
---|
| 221 | printf("foobar client: %s: ", qc_results[res]); |
---|
| 222 | |
---|
| 223 | if (answer->rrtype == kDNSType_PTR && |
---|
| 224 | (res == QC_rmv || res == QC_add)) { |
---|
| 225 | domainlabel name; |
---|
| 226 | mDNSBool ok = eval_service_name(&answer->rdata->u.name, &name); |
---|
| 227 | |
---|
| 228 | if (ok) { |
---|
| 229 | foobar_manage_service(m, answer, &name, res == QC_add); |
---|
| 230 | } |
---|
| 231 | |
---|
| 232 | printf("\n"); |
---|
| 233 | } |
---|
| 234 | } |
---|
| 235 | |
---|
| 236 | static void |
---|
| 237 | foobar_register(DNSQuestion *question) |
---|
| 238 | { |
---|
| 239 | mStatus status; |
---|
| 240 | domainname type; |
---|
| 241 | domainname domain; |
---|
| 242 | |
---|
| 243 | MakeDomainNameFromDNSNameString(&type, "_foobar._tcp"); |
---|
| 244 | MakeDomainNameFromDNSNameString(&domain, "local."); |
---|
| 245 | |
---|
| 246 | status = mDNS_StartBrowse(&mDNSStorage, question, &type, &domain, |
---|
| 247 | mDNSNULL, mDNSInterface_Any, 0, mDNSfalse, mDNSfalse, |
---|
| 248 | foobar_browse, NULL); |
---|
| 249 | assert(status == mStatus_NoError); |
---|
| 250 | } |
---|
| 251 | |
---|
| 252 | static void |
---|
| 253 | test_main(void) |
---|
| 254 | { |
---|
| 255 | mStatus status; |
---|
| 256 | DNSQuestion question; |
---|
| 257 | |
---|
| 258 | status = mDNS_Init(&mDNSStorage, &PlatformStorage, &rr_cache[0], |
---|
| 259 | sizeof(rr_cache) / sizeof(rr_cache[0]), |
---|
| 260 | mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, |
---|
| 261 | mDNS_Init_NoInitCallbackContext); |
---|
| 262 | assert(status == mStatus_NoError); |
---|
| 263 | |
---|
| 264 | foobar_register(&question); |
---|
| 265 | |
---|
| 266 | while (1) { |
---|
| 267 | struct timeval timeout = { .tv_sec = 0x3fffffff, .tv_usec = 0 }; |
---|
| 268 | sigset_t signals; |
---|
| 269 | mDNSBool got_something; |
---|
| 270 | |
---|
| 271 | mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals, &got_something); |
---|
| 272 | } |
---|
| 273 | } |
---|
| 274 | |
---|
| 275 | #define DEFAULT_NETWORK_DHCPCD_ENABLE |
---|
| 276 | #define DEFAULT_NETWORK_DHCPCD_NO_DHCP_DISCOVERY |
---|
| 277 | #define DEFAULT_NETWORK_SHELL |
---|
| 278 | |
---|
| 279 | #include <rtems/bsd/test/default-network-init.h> |
---|