1 /* posix.c 2 * 3 * Copyright (c) 2018-2021 Apple, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * utility functions common to all posix implementations (e.g., MacOS, Linux). 18 */ 19 20 #define _GNU_SOURCE 21 22 #include <netinet/in.h> 23 #include <net/if.h> 24 #ifndef LINUX 25 #include <netinet/in_var.h> 26 #include <net/if_dl.h> 27 #endif 28 #include <sys/ioctl.h> 29 #include <errno.h> 30 #include <ifaddrs.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <dirent.h> 34 #include <arpa/inet.h> 35 #include "dns_sd.h" 36 #include "srp.h" 37 #include "dns-msg.h" 38 #include "ioloop.h" 39 #ifdef SRP_TEST_SERVER 40 #include "test-api.h" 41 #endif 42 43 #undef OBJECT_TYPE 44 #define OBJECT_TYPE(x) int x##_created, x##_finalized, old_##x##_created, old_##x##_finalized; 45 #include "object-types.h" 46 47 void 48 ioloop_dump_object_allocation_stats(void) 49 { 50 #undef OBJECT_TYPE 51 #define OBJECT_TYPE(x) || (x ## _created != old_ ## x ## _created) || (x ## _finalized != old_ ## x ## _finalized) 52 if (false 53 #include "object-types.h" 54 ) 55 { 56 char outbuf[1000]; 57 char *obp = outbuf; 58 size_t len; 59 #undef OBJECT_TYPE 60 #define OBJECT_TYPE_STR(x) #x 61 #define OBJECT_TYPE(x) \ 62 len = snprintf(obp, (sizeof(outbuf)) - (obp - outbuf), OBJECT_TYPE_STR(x) " %d %d %d %d|", \ 63 old_ ## x ##_created, x ## _created, old_ ## x ## _finalized, x ## _finalized); \ 64 obp += len; \ 65 old_ ## x ## _created = x ## _created; \ 66 old_ ## x ## _finalized = x ## _finalized; \ 67 if (obp - outbuf > 900) { \ 68 INFO(PUB_S_SRP, outbuf); \ 69 obp = outbuf; \ 70 len = 0; \ 71 } 72 #include "object-types.h" 73 if (len > 0) { 74 INFO(PUB_S_SRP, outbuf); 75 } 76 } 77 int num_fds = get_num_fds(); 78 if (num_fds < 0) { 79 FAULT("out of file descriptors!!"); 80 abort(); 81 } 82 INFO("%d file descriptors in use", num_fds); 83 } 84 85 interface_address_state_t *interface_addresses; 86 87 void 88 ioloop_strcpy(char *dest, const char *src, size_t lim) 89 { 90 size_t len = strlen(src); 91 if (len >= lim - 1) { 92 len = lim - 1; 93 } 94 memcpy(dest, src, len); 95 dest[len] = 0; 96 } 97 98 bool 99 ioloop_map_interface_addresses(srp_server_t *server_state, const char *ifname, void *context, 100 interface_callback_t callback) 101 { 102 return ioloop_map_interface_addresses_here(server_state, &interface_addresses, ifname, context, callback); 103 } 104 105 static bool 106 ioloop_same_address(struct sockaddr *a, addr_t *b, struct sockaddr *ma, addr_t *sk) 107 { 108 // If the family is different, addresses are definitely not the same 109 if (a->sa_family != b->sa.sa_family) { 110 return false; 111 } 112 113 // For IPv4 addresses, both the address and the netmask must match 114 if (a->sa_family == AF_INET && b->sa.sa_family == AF_INET && ma->sa_family == AF_INET) { 115 struct sockaddr_in *a4 = (struct sockaddr_in *)a; 116 struct sockaddr_in *ma4 = (struct sockaddr_in *)ma; 117 118 if (a4->sin_addr.s_addr == b->sin.sin_addr.s_addr && ma4->sin_addr.s_addr == sk->sin.sin_addr.s_addr) { 119 return true; 120 } 121 } 122 123 // For IPv6 adddresses, same deal 124 else if (a->sa_family == AF_INET6 && b->sa.sa_family == AF_INET6 && ma->sa_family == AF_INET6) { 125 struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)a; 126 struct sockaddr_in6 *ma6 = (struct sockaddr_in6 *)ma; 127 128 if (!memcmp(&a6->sin6_addr, &b->sin6.sin6_addr, sizeof b->sin6.sin6_addr) && 129 !memcmp(&ma6->sin6_addr, &sk->sin6.sin6_addr, sizeof sk->sin6.sin6_addr)) 130 { 131 return true; 132 } 133 } 134 #ifndef LINUX 135 // For AF_LINK addresses, there is no netmask, and we are assuming a 6-byte ethernet address. 136 else if (a->sa_family == AF_LINK && b->sa.sa_family == AF_LINK) { 137 struct sockaddr_dl *sdl = (struct sockaddr_dl *)a; 138 if (sdl->sdl_alen == 6 && !memcmp(LLADDR(sdl), b->ether_addr.addr, 6) && b->ether_addr.index == sdl->sdl_index) 139 { 140 return true; 141 } 142 } 143 #endif 144 145 return false; // Unknown address family, don't know how to compare, don't really care. 146 } 147 148 bool 149 ioloop_map_interface_addresses_here_(srp_server_t *server_state, interface_address_state_t **here, const char *ifname, 150 void *context, interface_callback_t callback, const char *file, int line) 151 { 152 struct ifaddrs *ifaddrs, *ifp; 153 interface_address_state_t *kept_ifaddrs = NULL, **ki_end = &kept_ifaddrs; 154 interface_address_state_t *new_ifaddrs = NULL, **ni_end = &new_ifaddrs; 155 interface_address_state_t **ip, *nif; 156 157 #ifdef SRP_TEST_SERVER 158 int ret = srp_test_getifaddrs(server_state, &ifaddrs, context); 159 #else 160 int ret = getifaddrs(&ifaddrs); 161 #endif 162 if (ret < 0) { 163 ERROR("getifaddrs failed: " PUB_S_SRP, strerror(errno)); 164 return false; 165 } 166 167 for (ifp = ifaddrs; ifp; ifp = ifp->ifa_next) { 168 bool remove = false; 169 bool keep = true; 170 171 // It is impossible to have an interface without interface name. 172 if (ifp->ifa_name == NULL) { 173 continue; 174 } 175 if (ifname != NULL && strcmp(ifname, ifp->ifa_name)) { 176 continue; 177 } 178 179 #ifndef LINUX 180 // Check for temporary addresses, etc. 181 if (ifp->ifa_addr != NULL && ifp->ifa_addr->sa_family == AF_INET6) { 182 struct in6_ifreq ifreq; 183 int sock; 184 size_t len; 185 len = strlen(ifp->ifa_name); 186 if (len >= sizeof(ifreq.ifr_name)) { 187 len = sizeof(ifreq.ifr_name) - 1; 188 } 189 memcpy(ifreq.ifr_name, ifp->ifa_name, len); 190 ifreq.ifr_name[len] = 0; 191 if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 192 ERROR("socket(AF_INET6, SOCK_DGRAM): " PUB_S_SRP, strerror(errno)); 193 continue; 194 } 195 memcpy(&ifreq.ifr_addr, ifp->ifa_addr, sizeof ifreq.ifr_addr); 196 if (ioctl(sock, SIOCGIFAFLAG_IN6, &ifreq) < 0) { 197 ERROR("ioctl(SIOCGIFAFLAG_IN6): " PUB_S_SRP, strerror(errno)); 198 close(sock); 199 continue; 200 } 201 int flags = ifreq.ifr_ifru.ifru_flags6; 202 if (flags & (IN6_IFF_ANYCAST | IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_TEMPORARY)) { 203 keep = false; 204 } 205 if (flags & IN6_IFF_DEPRECATED) { 206 remove = true; 207 } 208 close(sock); 209 } 210 211 #ifdef DEBUG_AF_LINK 212 if (ifp->ifa_addr != NULL && ifp->ifa_addr->sa_family != AF_INET && ifp->ifa_addr->sa_family != AF_INET6) { 213 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifp->ifa_addr; 214 const uint8_t *addr = (uint8_t *)LLADDR(sdl); 215 INFO("%.*s index %d alen %d dlen %d SDL: %02x:%02x:%02x:%02x:%02x:%02x", 216 sdl->sdl_nlen, sdl->sdl_data, sdl->sdl_index, sdl->sdl_alen, sdl->sdl_slen, 217 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 218 } 219 #endif // DEBUG_AF_LINK 220 #endif // LINUX 221 222 // Is this an interface address we can use? 223 if (keep && ifp->ifa_addr != NULL && ( 224 #ifndef LINUX 225 ifp->ifa_addr->sa_family == AF_LINK || 226 #endif 227 ((ifp->ifa_addr->sa_family == AF_INET6 || ifp->ifa_addr->sa_family == AF_INET) && ifp->ifa_netmask != NULL)) && 228 (ifp->ifa_flags & IFF_UP)) 229 { 230 keep = false; 231 for (ip = here; *ip != NULL; ) { 232 interface_address_state_t *ia = *ip; 233 // Same interface and address? 234 if (!remove && !strcmp(ia->name, ifp->ifa_name) && 235 ioloop_same_address(ifp->ifa_addr, &ia->addr, ifp->ifa_netmask, &ia->mask)) 236 { 237 *ip = ia->next; 238 *ki_end = ia; 239 ki_end = &ia->next; 240 ia->next = NULL; 241 keep = true; 242 break; 243 } else { 244 ip = &ia->next; 245 } 246 } 247 // If keep is false, this is a new interface/address. 248 if (!keep) { 249 size_t len = strlen(ifp->ifa_name); 250 #ifdef MALLOC_DEBUG_LOGGING 251 nif = debug_calloc(1, len + 1 + sizeof(*nif), file, line); 252 #else 253 (void)file; 254 (void)line; 255 nif = calloc(1, len + 1 + sizeof(*nif)); 256 #endif 257 // We don't have a way to fix nif being null; what this means is that we don't detect a new 258 // interface address. 259 if (nif != NULL) { 260 nif->name = (char *)(nif + 1); 261 memcpy(nif->name, ifp->ifa_name, len); 262 nif->name[len] = 0; 263 if (ifp->ifa_addr->sa_family == AF_INET) { 264 nif->addr.sin = *((struct sockaddr_in *)ifp->ifa_addr); 265 nif->mask.sin = *((struct sockaddr_in *)ifp->ifa_netmask); 266 267 IPv4_ADDR_GEN_SRP(&nif->addr.sin.sin_addr.s_addr, __new_interface_ipv4_addr); 268 INFO("new IPv4 interface address added - ifname: " PUB_S_SRP 269 ", addr: " PRI_IPv4_ADDR_SRP, nif->name, 270 IPv4_ADDR_PARAM_SRP(&nif->addr.sin.sin_addr.s_addr, __new_interface_ipv4_addr)); 271 } else if (ifp->ifa_addr->sa_family == AF_INET6) { 272 nif->addr.sin6 = *((struct sockaddr_in6 *)ifp->ifa_addr); 273 nif->mask.sin6 = *((struct sockaddr_in6 *)ifp->ifa_netmask); 274 275 SEGMENTED_IPv6_ADDR_GEN_SRP(nif->addr.sin6.sin6_addr.s6_addr, __new_interface_ipv6_addr); 276 INFO("new IPv6 interface address added - ifname: " PUB_S_SRP 277 ", addr: " PRI_SEGMENTED_IPv6_ADDR_SRP, nif->name, 278 SEGMENTED_IPv6_ADDR_PARAM_SRP(nif->addr.sin6.sin6_addr.s6_addr, 279 __new_interface_ipv6_addr)); 280 } else { 281 #ifndef LINUX 282 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifp->ifa_addr; 283 memset(&nif->mask, 0, sizeof(nif->mask)); 284 if (sdl->sdl_alen == 6) { 285 nif->addr.ether_addr.len = 6; 286 memcpy(nif->addr.ether_addr.addr, LLADDR(sdl), 6); 287 nif->addr.ether_addr.index = sdl->sdl_index; 288 nif->addr.ether_addr.family = AF_LINK; 289 } else { 290 free(nif); 291 nif = NULL; 292 } 293 294 #endif // LINUX 295 } 296 if (nif != NULL) { 297 nif->flags = ifp->ifa_flags; 298 *ni_end = nif; 299 ni_end = &nif->next; 300 } 301 } 302 } 303 } 304 } 305 306 #ifndef LINUX 307 // Get rid of any link-layer addresses for which there is no other address on that interface 308 // This is clunky, but we can't assume that the AF_LINK address will come after some other 309 // address, so there's no more efficient way to do this that I can think of. 310 for (ip = &new_ifaddrs; *ip; ) { 311 if ((*ip)->addr.sa.sa_family == AF_LINK) { 312 bool drop = true; 313 // We need to iterate across both new_ifaddrs and kept_ifaddrs to find all of the addresses on an 314 // interface. Only if there are no IP addresses on either list for the interface for which we have 315 // the AF_LINK address do we drop the AF_LINK address. 316 for (int q = 0; q < 2; q++) { 317 interface_address_state_t *list = q ? kept_ifaddrs : new_ifaddrs; 318 for (nif = list; nif; nif = nif->next) { 319 if (nif != *ip && nif->addr.sa.sa_family != AF_LINK && !strcmp(nif->name, (*ip)->name)) { 320 #define TOO_MUCH_INFO 321 #ifdef TOO_MUCH_INFO 322 char buf[INET6_ADDRSTRLEN]; 323 if (nif->addr.sa.sa_family == AF_INET6) { 324 inet_ntop(AF_INET6, &nif->addr.sin6.sin6_addr, buf, sizeof(buf)); 325 } else if (nif->addr.sa.sa_family == AF_INET) { 326 inet_ntop(AF_INET, &nif->addr.sin6.sin6_addr, buf, sizeof(buf)); 327 } 328 INFO("new link-layer address not dropped because " PRI_S_SRP " - ifname: " PUB_S_SRP ", addr: " 329 PRI_MAC_ADDR_SRP, buf, (*ip)->name, MAC_ADDR_PARAM_SRP((*ip)->addr.ether_addr.addr)); 330 #endif // TOO_MUCH_INFO 331 drop = false; 332 break; 333 } 334 } 335 } 336 if (drop) { 337 #ifdef TOO_MUCH_INFO 338 INFO("new link-layer interface address dropped - ifname: " PUB_S_SRP 339 ", addr: " PRI_MAC_ADDR_SRP, (*ip)->name, MAC_ADDR_PARAM_SRP((*ip)->addr.ether_addr.addr)); 340 #endif 341 nif = *ip; 342 *ip = nif->next; 343 free(nif); 344 } else { 345 ip = &(*ip)->next; 346 } 347 } else { 348 ip = &(*ip)->next; 349 } 350 } 351 #endif // LINUX 352 353 #ifdef TOO_MUCH_INFO 354 char infobuf[1000]; 355 int i; 356 for (i = 0; i < 3; i++) { 357 char *infop = infobuf; 358 int len, lim = sizeof infobuf; 359 const char *title; 360 switch(i) { 361 case 0: 362 title = "deleted"; 363 nif = *here; 364 break; 365 case 1: 366 title = " kept"; 367 nif = kept_ifaddrs; 368 break; 369 case 2: 370 title = " new"; 371 nif = new_ifaddrs; 372 break; 373 default: 374 abort(); 375 } 376 for (; nif; nif = nif->next) { 377 snprintf(infop, lim, "\n%p %s (", nif, nif->name); 378 len = (int)strlen(infop); 379 lim -= len; 380 infop += len; 381 if (nif->addr.sa.sa_family == AF_INET6) { 382 inet_ntop(AF_INET6, &nif->addr.sin6.sin6_addr, infop, lim); 383 } else if (nif->addr.sa.sa_family == AF_INET) { 384 inet_ntop(AF_INET, &nif->addr.sin.sin_addr, infop, lim); 385 } else if (nif->addr.sa.sa_family == AF_LINK) { 386 snprintf(infop, lim, "%02x:%02x:%02x:%02x:%02x:%02x", 387 nif->addr.ether_addr.addr[0], nif->addr.ether_addr.addr[1], nif->addr.ether_addr.addr[2], 388 nif->addr.ether_addr.addr[3], nif->addr.ether_addr.addr[4], nif->addr.ether_addr.addr[5]); 389 } 390 len = (int)strlen(infop); 391 lim -= len; 392 infop += len; 393 if (lim > 1) { 394 *infop++ = ')'; 395 lim--; 396 } 397 } 398 *infop = 0; 399 INFO(PUB_S_SRP ":" PUB_S_SRP, title, infobuf); 400 } 401 #endif 402 403 // Report and free deleted interface addresses... 404 for (ip = here; *ip; ) { 405 nif = *ip; 406 *ip = nif->next; 407 if (callback != NULL) { 408 callback(server_state, context, nif->name, &nif->addr, &nif->mask, nif->flags, interface_address_deleted); 409 } 410 free(nif); 411 } 412 413 // Report added interface addresses... 414 for (nif = new_ifaddrs; nif; nif = nif->next) { 415 if (callback != NULL) { 416 callback(server_state, context, nif->name, &nif->addr, &nif->mask, nif->flags, interface_address_added); 417 } 418 } 419 420 // Report unchanged interface addresses... 421 for (nif = kept_ifaddrs; nif; nif = nif->next) { 422 if (callback != NULL) { 423 callback(server_state, context, nif->name, &nif->addr, &nif->mask, nif->flags, interface_address_unchanged); 424 } 425 } 426 427 // Restore kept interface addresses and append new addresses to the list. 428 *here = kept_ifaddrs; 429 for (ip = here; *ip; ip = &(*ip)->next) 430 ; 431 *ip = new_ifaddrs; 432 #ifdef SRP_TEST_SERVER 433 srp_test_freeifaddrs(server_state, ifaddrs, context); 434 #else 435 freeifaddrs(ifaddrs); 436 #endif 437 return true; 438 } 439 440 ssize_t 441 ioloop_recvmsg(int sock, uint8_t *buffer, size_t buffer_length, int *ifindex, int *hop_limit, addr_t *source, 442 addr_t *destination) 443 { 444 ssize_t rv; 445 struct msghdr msg; 446 struct iovec bufp; 447 char cmsgbuf[128]; 448 struct cmsghdr *cmh; 449 450 bufp.iov_base = buffer; 451 bufp.iov_len = buffer_length; 452 msg.msg_iov = &bufp; 453 msg.msg_iovlen = 1; 454 msg.msg_name = source; 455 msg.msg_namelen = sizeof(*source); 456 msg.msg_control = cmsgbuf; 457 msg.msg_controllen = sizeof(cmsgbuf); 458 459 rv = recvmsg(sock, &msg, 0); 460 if (rv < 0) { 461 return rv; 462 } 463 464 // For UDP, we use the interface index as part of the validation strategy, so go get 465 // the interface index. 466 for (cmh = CMSG_FIRSTHDR(&msg); cmh; cmh = CMSG_NXTHDR(&msg, cmh)) { 467 if (cmh->cmsg_level == IPPROTO_IPV6 && cmh->cmsg_type == IPV6_PKTINFO && 468 cmh->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) 469 { 470 struct in6_pktinfo pktinfo; 471 472 memcpy(&pktinfo, CMSG_DATA(cmh), sizeof pktinfo); 473 *ifindex = (int)pktinfo.ipi6_ifindex; 474 475 /* Get the destination address, for use when replying. */ 476 destination->sin6.sin6_family = AF_INET6; 477 destination->sin6.sin6_port = 0; 478 destination->sin6.sin6_addr = pktinfo.ipi6_addr; 479 #ifndef NOT_HAVE_SA_LEN 480 destination->sin6.sin6_len = sizeof(destination->sin6); 481 #endif 482 } else if (cmh->cmsg_level == IPPROTO_IP && cmh->cmsg_type == IP_PKTINFO && 483 cmh->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) { 484 struct in_pktinfo pktinfo; 485 486 memcpy(&pktinfo, CMSG_DATA(cmh), sizeof pktinfo); 487 *ifindex = (int)pktinfo.ipi_ifindex; 488 489 destination->sin.sin_family = AF_INET; 490 destination->sin.sin_port = 0; 491 destination->sin.sin_addr = pktinfo.ipi_addr; 492 #ifndef NOT_HAVE_SA_LEN 493 destination->sin.sin_len = sizeof(destination->sin); 494 #endif 495 } else if (cmh->cmsg_level == IPPROTO_IPV6 && cmh->cmsg_type == IPV6_HOPLIMIT && 496 cmh->cmsg_len == CMSG_LEN(sizeof(int))) { 497 *hop_limit = *(int *)CMSG_DATA(cmh); 498 } 499 } 500 return rv; 501 } 502 503 message_t * 504 ioloop_message_create_(size_t message_size, const char *file, int line) 505 { 506 message_t *message; 507 508 // Never should have a message shorter than this. 509 if (message_size < DNS_HEADER_SIZE || message_size > UINT16_MAX) { 510 return NULL; 511 } 512 513 message = (message_t *)malloc(message_size + (sizeof(message_t)) - (sizeof(dns_wire_t))); 514 if (message) { 515 memset(message, 0, (sizeof(message_t)) - (sizeof(dns_wire_t))); 516 RETAIN(message, message); 517 message->length = (uint16_t)message_size; 518 } 519 return message; 520 } 521 522 // Return continuous time, if provided by O.S., otherwise unadjusted time. 523 time_t 524 srp_time(void) 525 { 526 #ifdef CLOCK_BOOTTIME 527 // CLOCK_BOOTTIME is a Linux-specific constant that indicates a monotonic time that includes time asleep 528 const int clockid = CLOCK_BOOTTIME; 529 #elif defined(CLOCK_MONOTONIC_RAW) 530 // On MacOS, CLOCK_MONOTONIC_RAW is a monotonic time that includes time asleep and is not adjusted. 531 // According to the man page, CLOCK_MONOTONIC on MacOS violates the POSIX spec in that it can be adjusted. 532 const int clockid = CLOCK_MONOTONIC_RAW; 533 #else 534 // On other Posix systems, CLOCK_MONOTONIC should be the right thing, at least according to the POSIX spec. 535 const int clockid = CLOCK_MONOTONIC; 536 #endif 537 struct timespec tm; 538 clock_gettime(clockid, &tm); 539 540 // We are only accurate to the second. 541 return tm.tv_sec; 542 } 543 544 // Return continuous time, if provided by O.S., otherwise unadjusted time, in seconds, with six digits of 545 // fractional accuracy. 546 double 547 srp_fractional_time(void) 548 { 549 #ifdef CLOCK_BOOTTIME 550 // CLOCK_BOOTTIME is a Linux-specific constant that indicates a monotonic time that includes time asleep 551 const int clockid = CLOCK_BOOTTIME; 552 #elif defined(CLOCK_MONOTONIC_RAW) 553 // On MacOS, CLOCK_MONOTONIC_RAW is a monotonic time that includes time asleep and is not adjusted. 554 // According to the man page, CLOCK_MONOTONIC on MacOS violates the POSIX spec in that it can be adjusted. 555 const int clockid = CLOCK_MONOTONIC_RAW; 556 #else 557 // On other Posix systems, CLOCK_MONOTONIC should be the right thing, at least according to the POSIX spec. 558 const int clockid = CLOCK_MONOTONIC; 559 #endif 560 struct timespec tm; 561 clock_gettime(clockid, &tm); 562 563 return (double)tm.tv_sec + (double)tm.tv_nsec / 1.0e9; 564 } 565 566 // Return continuous time in microseconds, if provided by O.S., otherwise unadjusted time. 567 int64_t 568 srp_utime(void) 569 { 570 #ifdef CLOCK_BOOTTIME 571 // CLOCK_BOOTTIME is a Linux-specific constant that indicates a monotonic time that includes time asleep 572 const int clockid = CLOCK_BOOTTIME; 573 #elif defined(CLOCK_MONOTONIC_RAW) 574 // On MacOS, CLOCK_MONOTONIC_RAW is a monotonic time that includes time asleep and is not adjusted. 575 // According to the man page, CLOCK_MONOTONIC on MacOS violates the POSIX spec in that it can be adjusted. 576 const int clockid = CLOCK_MONOTONIC_RAW; 577 #else 578 // On other Posix systems, CLOCK_MONOTONIC should be the right thing, at least according to the POSIX spec. 579 const int clockid = CLOCK_MONOTONIC; 580 #endif 581 struct timespec tm; 582 clock_gettime(clockid, &tm); 583 584 // We are only accurate to the second. 585 uint64_t utime = (int64_t)tm.tv_sec * 1000 * 1000 + tm.tv_nsec / 1000; 586 return utime; 587 } 588 589 int 590 get_num_fds(void) 591 { 592 int num = 0; 593 DIR *dirfd = opendir("/dev/fd"); 594 if (dirfd == NULL) { 595 if (errno == EMFILE) { 596 FAULT("per-process open file limit reached."); 597 return -1; 598 } else if (errno == ENFILE) { 599 FAULT("per-system open file limit reached."); 600 return -1; 601 } else { 602 ERROR("errno %d " PUB_S_SRP, errno, strerror(errno)); 603 return 0; 604 } 605 } 606 while (readdir(dirfd) != NULL) { 607 num++; 608 } 609 closedir(dirfd); 610 return num; 611 } 612 613 #ifdef MALLOC_DEBUG_LOGGING 614 #undef malloc 615 #undef calloc 616 #undef strdup 617 #undef free 618 619 void * 620 debug_malloc(size_t len, const char *file, int line) 621 { 622 void *ret = malloc(len); 623 INFO("%p: malloc(%zu) at " PUB_S_SRP ":%d", ret, len, file, line); 624 return ret; 625 } 626 627 void * 628 debug_calloc(size_t count, size_t len, const char *file, int line) 629 { 630 void *ret = calloc(count, len); 631 INFO("%p: calloc(%zu, %zu) at " PUB_S_SRP ":%d", ret, count, len, file, line); 632 return ret; 633 } 634 635 char * 636 debug_strdup(const char *s, const char *file, int line) 637 { 638 char *ret = strdup(s); 639 INFO("%p: strdup(%p) at " PUB_S_SRP ":%d", ret, s, file, line); 640 return ret; 641 } 642 643 void 644 debug_free(void *p, const char *file, int line) 645 { 646 INFO("%p: free() at " PUB_S_SRP ":%d", p, file, line); 647 free(p); 648 } 649 #endif 650 651 // Local Variables: 652 // mode: C 653 // tab-width: 4 654 // c-file-style: "bsd" 655 // c-basic-offset: 4 656 // fill-column: 108 657 // indent-tabs-mode: nil 658 // End: 659