Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Utilities / cmlibuv / src / unix / sunos.c
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  * Permission is hereby granted, free of charge, to any person obtaining a copy
3  * of this software and associated documentation files (the "Software"), to
4  * deal in the Software without restriction, including without limitation the
5  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6  * sell copies of the Software, and to permit persons to whom the Software is
7  * furnished to do so, subject to the following conditions:
8  *
9  * The above copyright notice and this permission notice shall be included in
10  * all copies or substantial portions of the Software.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18  * IN THE SOFTWARE.
19  */
20
21 #include "uv.h"
22 #include "internal.h"
23
24 #include <stdio.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30
31 #if !defined(SUNOS_NO_IFADDRS) && _XOPEN_SOURCE < 600
32 #define SUNOS_NO_IFADDRS
33 #endif
34
35 #ifndef SUNOS_NO_IFADDRS
36 # include <ifaddrs.h>
37 #endif
38 #include <net/if.h>
39 #include <net/if_dl.h>
40 #include <net/if_arp.h>
41 #include <sys/sockio.h>
42
43 #include <sys/loadavg.h>
44 #include <sys/time.h>
45 #include <unistd.h>
46 #include <kstat.h>
47 #include <fcntl.h>
48
49 #include <sys/port.h>
50 #include <port.h>
51
52 #define PORT_FIRED 0x69
53 #define PORT_UNUSED 0x0
54 #define PORT_LOADED 0x99
55 #define PORT_DELETED -1
56
57 #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
58 #define PROCFS_FILE_OFFSET_BITS_HACK 1
59 #undef _FILE_OFFSET_BITS
60 #else
61 #define PROCFS_FILE_OFFSET_BITS_HACK 0
62 #endif
63
64 #include <procfs.h>
65
66 #if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
67 #define _FILE_OFFSET_BITS 64
68 #endif
69
70
71 int uv__platform_loop_init(uv_loop_t* loop) {
72   int err;
73   int fd;
74
75   loop->fs_fd = -1;
76   loop->backend_fd = -1;
77
78   fd = port_create();
79   if (fd == -1)
80     return UV__ERR(errno);
81
82   err = uv__cloexec(fd, 1);
83   if (err) {
84     uv__close(fd);
85     return err;
86   }
87   loop->backend_fd = fd;
88
89   return 0;
90 }
91
92
93 void uv__platform_loop_delete(uv_loop_t* loop) {
94   if (loop->fs_fd != -1) {
95     uv__close(loop->fs_fd);
96     loop->fs_fd = -1;
97   }
98
99   if (loop->backend_fd != -1) {
100     uv__close(loop->backend_fd);
101     loop->backend_fd = -1;
102   }
103 }
104
105
106 int uv__io_fork(uv_loop_t* loop) {
107 #if defined(PORT_SOURCE_FILE)
108   if (loop->fs_fd != -1) {
109     /* stop the watcher before we blow away its fileno */
110     uv__io_stop(loop, &loop->fs_event_watcher, POLLIN);
111   }
112 #endif
113   uv__platform_loop_delete(loop);
114   return uv__platform_loop_init(loop);
115 }
116
117
118 void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
119   struct port_event* events;
120   uintptr_t i;
121   uintptr_t nfds;
122
123   assert(loop->watchers != NULL);
124   assert(fd >= 0);
125
126   events = (struct port_event*) loop->watchers[loop->nwatchers];
127   nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
128   if (events == NULL)
129     return;
130
131   /* Invalidate events with same file descriptor */
132   for (i = 0; i < nfds; i++)
133     if ((int) events[i].portev_object == fd)
134       events[i].portev_object = -1;
135 }
136
137
138 int uv__io_check_fd(uv_loop_t* loop, int fd) {
139   if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0))
140     return UV__ERR(errno);
141
142   if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) {
143     perror("(libuv) port_dissociate()");
144     abort();
145   }
146
147   return 0;
148 }
149
150
151 void uv__io_poll(uv_loop_t* loop, int timeout) {
152   struct port_event events[1024];
153   struct port_event* pe;
154   struct timespec spec;
155   QUEUE* q;
156   uv__io_t* w;
157   sigset_t* pset;
158   sigset_t set;
159   uint64_t base;
160   uint64_t diff;
161   unsigned int nfds;
162   unsigned int i;
163   int saved_errno;
164   int have_signals;
165   int nevents;
166   int count;
167   int err;
168   int fd;
169   int user_timeout;
170   int reset_timeout;
171
172   if (loop->nfds == 0) {
173     assert(QUEUE_EMPTY(&loop->watcher_queue));
174     return;
175   }
176
177   while (!QUEUE_EMPTY(&loop->watcher_queue)) {
178     q = QUEUE_HEAD(&loop->watcher_queue);
179     QUEUE_REMOVE(q);
180     QUEUE_INIT(q);
181
182     w = QUEUE_DATA(q, uv__io_t, watcher_queue);
183     assert(w->pevents != 0);
184
185     if (port_associate(loop->backend_fd,
186                        PORT_SOURCE_FD,
187                        w->fd,
188                        w->pevents,
189                        0)) {
190       perror("(libuv) port_associate()");
191       abort();
192     }
193
194     w->events = w->pevents;
195   }
196
197   pset = NULL;
198   if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
199     pset = &set;
200     sigemptyset(pset);
201     sigaddset(pset, SIGPROF);
202   }
203
204   assert(timeout >= -1);
205   base = loop->time;
206   count = 48; /* Benchmarks suggest this gives the best throughput. */
207
208   if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
209     reset_timeout = 1;
210     user_timeout = timeout;
211     timeout = 0;
212   } else {
213     reset_timeout = 0;
214   }
215
216   for (;;) {
217     /* Only need to set the provider_entry_time if timeout != 0. The function
218      * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
219      */
220     if (timeout != 0)
221       uv__metrics_set_provider_entry_time(loop);
222
223     if (timeout != -1) {
224       spec.tv_sec = timeout / 1000;
225       spec.tv_nsec = (timeout % 1000) * 1000000;
226     }
227
228     /* Work around a kernel bug where nfds is not updated. */
229     events[0].portev_source = 0;
230
231     nfds = 1;
232     saved_errno = 0;
233
234     if (pset != NULL)
235       pthread_sigmask(SIG_BLOCK, pset, NULL);
236
237     err = port_getn(loop->backend_fd,
238                     events,
239                     ARRAY_SIZE(events),
240                     &nfds,
241                     timeout == -1 ? NULL : &spec);
242
243     if (pset != NULL)
244       pthread_sigmask(SIG_UNBLOCK, pset, NULL);
245
246     if (err) {
247       /* Work around another kernel bug: port_getn() may return events even
248        * on error.
249        */
250       if (errno == EINTR || errno == ETIME) {
251         saved_errno = errno;
252       } else {
253         perror("(libuv) port_getn()");
254         abort();
255       }
256     }
257
258     /* Update loop->time unconditionally. It's tempting to skip the update when
259      * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
260      * operating system didn't reschedule our process while in the syscall.
261      */
262     SAVE_ERRNO(uv__update_time(loop));
263
264     if (events[0].portev_source == 0) {
265       if (reset_timeout != 0) {
266         timeout = user_timeout;
267         reset_timeout = 0;
268       }
269
270       if (timeout == 0)
271         return;
272
273       if (timeout == -1)
274         continue;
275
276       goto update_timeout;
277     }
278
279     if (nfds == 0) {
280       assert(timeout != -1);
281       return;
282     }
283
284     have_signals = 0;
285     nevents = 0;
286
287     assert(loop->watchers != NULL);
288     loop->watchers[loop->nwatchers] = (void*) events;
289     loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
290     for (i = 0; i < nfds; i++) {
291       pe = events + i;
292       fd = pe->portev_object;
293
294       /* Skip invalidated events, see uv__platform_invalidate_fd */
295       if (fd == -1)
296         continue;
297
298       assert(fd >= 0);
299       assert((unsigned) fd < loop->nwatchers);
300
301       w = loop->watchers[fd];
302
303       /* File descriptor that we've stopped watching, ignore. */
304       if (w == NULL)
305         continue;
306
307       /* Run signal watchers last.  This also affects child process watchers
308        * because those are implemented in terms of signal watchers.
309        */
310       if (w == &loop->signal_io_watcher) {
311         have_signals = 1;
312       } else {
313         uv__metrics_update_idle_time(loop);
314         w->cb(loop, w, pe->portev_events);
315       }
316
317       nevents++;
318
319       if (w != loop->watchers[fd])
320         continue;  /* Disabled by callback. */
321
322       /* Events Ports operates in oneshot mode, rearm timer on next run. */
323       if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
324         QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
325     }
326
327     if (reset_timeout != 0) {
328       timeout = user_timeout;
329       reset_timeout = 0;
330     }
331
332     if (have_signals != 0) {
333       uv__metrics_update_idle_time(loop);
334       loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
335     }
336
337     loop->watchers[loop->nwatchers] = NULL;
338     loop->watchers[loop->nwatchers + 1] = NULL;
339
340     if (have_signals != 0)
341       return;  /* Event loop should cycle now so don't poll again. */
342
343     if (nevents != 0) {
344       if (nfds == ARRAY_SIZE(events) && --count != 0) {
345         /* Poll for more events but don't block this time. */
346         timeout = 0;
347         continue;
348       }
349       return;
350     }
351
352     if (saved_errno == ETIME) {
353       assert(timeout != -1);
354       return;
355     }
356
357     if (timeout == 0)
358       return;
359
360     if (timeout == -1)
361       continue;
362
363 update_timeout:
364     assert(timeout > 0);
365
366     diff = loop->time - base;
367     if (diff >= (uint64_t) timeout)
368       return;
369
370     timeout -= diff;
371   }
372 }
373
374
375 uint64_t uv__hrtime(uv_clocktype_t type) {
376   return gethrtime();
377 }
378
379
380 /*
381  * We could use a static buffer for the path manipulations that we need outside
382  * of the function, but this function could be called by multiple consumers and
383  * we don't want to potentially create a race condition in the use of snprintf.
384  */
385 int uv_exepath(char* buffer, size_t* size) {
386   ssize_t res;
387   char buf[128];
388
389   if (buffer == NULL || size == NULL || *size == 0)
390     return UV_EINVAL;
391
392   snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
393
394   res = *size - 1;
395   if (res > 0)
396     res = readlink(buf, buffer, res);
397
398   if (res == -1)
399     return UV__ERR(errno);
400
401   buffer[res] = '\0';
402   *size = res;
403   return 0;
404 }
405
406
407 uint64_t uv_get_free_memory(void) {
408   return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
409 }
410
411
412 uint64_t uv_get_total_memory(void) {
413   return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
414 }
415
416
417 uint64_t uv_get_constrained_memory(void) {
418   return 0;  /* Memory constraints are unknown. */
419 }
420
421
422 void uv_loadavg(double avg[3]) {
423   (void) getloadavg(avg, 3);
424 }
425
426
427 #if defined(PORT_SOURCE_FILE)
428
429 static int uv__fs_event_rearm(uv_fs_event_t *handle) {
430   if (handle->fd == PORT_DELETED)
431     return UV_EBADF;
432
433   if (port_associate(handle->loop->fs_fd,
434                      PORT_SOURCE_FILE,
435                      (uintptr_t) &handle->fo,
436                      FILE_ATTRIB | FILE_MODIFIED,
437                      handle) == -1) {
438     return UV__ERR(errno);
439   }
440   handle->fd = PORT_LOADED;
441
442   return 0;
443 }
444
445
446 static void uv__fs_event_read(uv_loop_t* loop,
447                               uv__io_t* w,
448                               unsigned int revents) {
449   uv_fs_event_t *handle = NULL;
450   timespec_t timeout;
451   port_event_t pe;
452   int events;
453   int r;
454
455   (void) w;
456   (void) revents;
457
458   do {
459     uint_t n = 1;
460
461     /*
462      * Note that our use of port_getn() here (and not port_get()) is deliberate:
463      * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
464      * causes port_get() to return success instead of ETIME when there aren't
465      * actually any events (!); by using port_getn() in lieu of port_get(),
466      * we can at least workaround the bug by checking for zero returned events
467      * and treating it as we would ETIME.
468      */
469     do {
470       memset(&timeout, 0, sizeof timeout);
471       r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
472     }
473     while (r == -1 && errno == EINTR);
474
475     if ((r == -1 && errno == ETIME) || n == 0)
476       break;
477
478     handle = (uv_fs_event_t*) pe.portev_user;
479     assert((r == 0) && "unexpected port_get() error");
480
481     if (uv__is_closing(handle)) {
482       uv__handle_stop(handle);
483       uv__make_close_pending((uv_handle_t*) handle);
484       break;
485     }
486
487     events = 0;
488     if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
489       events |= UV_CHANGE;
490     if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
491       events |= UV_RENAME;
492     assert(events != 0);
493     handle->fd = PORT_FIRED;
494     handle->cb(handle, NULL, events, 0);
495
496     if (handle->fd != PORT_DELETED) {
497       r = uv__fs_event_rearm(handle);
498       if (r != 0)
499         handle->cb(handle, NULL, 0, r);
500     }
501   }
502   while (handle->fd != PORT_DELETED);
503 }
504
505
506 int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
507   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
508   return 0;
509 }
510
511
512 int uv_fs_event_start(uv_fs_event_t* handle,
513                       uv_fs_event_cb cb,
514                       const char* path,
515                       unsigned int flags) {
516   int portfd;
517   int first_run;
518   int err;
519
520   if (uv__is_active(handle))
521     return UV_EINVAL;
522
523   first_run = 0;
524   if (handle->loop->fs_fd == -1) {
525     portfd = port_create();
526     if (portfd == -1)
527       return UV__ERR(errno);
528     handle->loop->fs_fd = portfd;
529     first_run = 1;
530   }
531
532   uv__handle_start(handle);
533   handle->path = uv__strdup(path);
534   handle->fd = PORT_UNUSED;
535   handle->cb = cb;
536
537   memset(&handle->fo, 0, sizeof handle->fo);
538   handle->fo.fo_name = handle->path;
539   err = uv__fs_event_rearm(handle);
540   if (err != 0) {
541     uv_fs_event_stop(handle);
542     return err;
543   }
544
545   if (first_run) {
546     uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
547     uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN);
548   }
549
550   return 0;
551 }
552
553
554 static int uv__fs_event_stop(uv_fs_event_t* handle) {
555   int ret = 0;
556
557   if (!uv__is_active(handle))
558     return 0;
559
560   if (handle->fd == PORT_LOADED) {
561     ret = port_dissociate(handle->loop->fs_fd,
562                     PORT_SOURCE_FILE,
563                     (uintptr_t) &handle->fo);
564   }
565
566   handle->fd = PORT_DELETED;
567   uv__free(handle->path);
568   handle->path = NULL;
569   handle->fo.fo_name = NULL;
570   if (ret == 0)
571     uv__handle_stop(handle);
572
573   return ret;
574 }
575
576 int uv_fs_event_stop(uv_fs_event_t* handle) {
577   (void) uv__fs_event_stop(handle);
578   return 0;
579 }
580
581 void uv__fs_event_close(uv_fs_event_t* handle) {
582   /*
583    * If we were unable to dissociate the port here, then it is most likely
584    * that there is a pending queued event. When this happens, we don't want
585    * to complete the close as it will free the underlying memory for the
586    * handle, causing a use-after-free problem when the event is processed.
587    * We defer the final cleanup until after the event is consumed in
588    * uv__fs_event_read().
589    */
590   if (uv__fs_event_stop(handle) == 0)
591     uv__make_close_pending((uv_handle_t*) handle);
592 }
593
594 #else /* !defined(PORT_SOURCE_FILE) */
595
596 int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
597   return UV_ENOSYS;
598 }
599
600
601 int uv_fs_event_start(uv_fs_event_t* handle,
602                       uv_fs_event_cb cb,
603                       const char* filename,
604                       unsigned int flags) {
605   return UV_ENOSYS;
606 }
607
608
609 int uv_fs_event_stop(uv_fs_event_t* handle) {
610   return UV_ENOSYS;
611 }
612
613
614 void uv__fs_event_close(uv_fs_event_t* handle) {
615   UNREACHABLE();
616 }
617
618 #endif /* defined(PORT_SOURCE_FILE) */
619
620
621 int uv_resident_set_memory(size_t* rss) {
622   psinfo_t psinfo;
623   int err;
624   int fd;
625
626   fd = open("/proc/self/psinfo", O_RDONLY);
627   if (fd == -1)
628     return UV__ERR(errno);
629
630   /* FIXME(bnoordhuis) Handle EINTR. */
631   err = UV_EINVAL;
632   if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
633     *rss = (size_t)psinfo.pr_rssize * 1024;
634     err = 0;
635   }
636   uv__close(fd);
637
638   return err;
639 }
640
641
642 int uv_uptime(double* uptime) {
643   kstat_ctl_t   *kc;
644   kstat_t       *ksp;
645   kstat_named_t *knp;
646
647   long hz = sysconf(_SC_CLK_TCK);
648
649   kc = kstat_open();
650   if (kc == NULL)
651     return UV_EPERM;
652
653   ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
654   if (kstat_read(kc, ksp, NULL) == -1) {
655     *uptime = -1;
656   } else {
657     knp = (kstat_named_t*)  kstat_data_lookup(ksp, (char*) "clk_intr");
658     *uptime = knp->value.ul / hz;
659   }
660   kstat_close(kc);
661
662   return 0;
663 }
664
665
666 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
667   int           lookup_instance;
668   kstat_ctl_t   *kc;
669   kstat_t       *ksp;
670   kstat_named_t *knp;
671   uv_cpu_info_t* cpu_info;
672
673   kc = kstat_open();
674   if (kc == NULL)
675     return UV_EPERM;
676
677   /* Get count of cpus */
678   lookup_instance = 0;
679   while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
680     lookup_instance++;
681   }
682
683   *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos));
684   if (!(*cpu_infos)) {
685     kstat_close(kc);
686     return UV_ENOMEM;
687   }
688
689   *count = lookup_instance;
690
691   cpu_info = *cpu_infos;
692   lookup_instance = 0;
693   while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
694     if (kstat_read(kc, ksp, NULL) == -1) {
695       cpu_info->speed = 0;
696       cpu_info->model = NULL;
697     } else {
698       knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
699       assert(knp->data_type == KSTAT_DATA_INT32 ||
700              knp->data_type == KSTAT_DATA_INT64);
701       cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
702                                                              : knp->value.i64;
703
704       knp = kstat_data_lookup(ksp, (char*) "brand");
705       assert(knp->data_type == KSTAT_DATA_STRING);
706       cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp));
707     }
708
709     lookup_instance++;
710     cpu_info++;
711   }
712
713   cpu_info = *cpu_infos;
714   lookup_instance = 0;
715   for (;;) {
716     ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
717
718     if (ksp == NULL)
719       break;
720
721     if (kstat_read(kc, ksp, NULL) == -1) {
722       cpu_info->cpu_times.user = 0;
723       cpu_info->cpu_times.nice = 0;
724       cpu_info->cpu_times.sys = 0;
725       cpu_info->cpu_times.idle = 0;
726       cpu_info->cpu_times.irq = 0;
727     } else {
728       knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
729       assert(knp->data_type == KSTAT_DATA_UINT64);
730       cpu_info->cpu_times.user = knp->value.ui64;
731
732       knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
733       assert(knp->data_type == KSTAT_DATA_UINT64);
734       cpu_info->cpu_times.sys = knp->value.ui64;
735
736       knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
737       assert(knp->data_type == KSTAT_DATA_UINT64);
738       cpu_info->cpu_times.idle = knp->value.ui64;
739
740       knp = kstat_data_lookup(ksp, (char*) "intr");
741       assert(knp->data_type == KSTAT_DATA_UINT64);
742       cpu_info->cpu_times.irq = knp->value.ui64;
743       cpu_info->cpu_times.nice = 0;
744     }
745
746     lookup_instance++;
747     cpu_info++;
748   }
749
750   kstat_close(kc);
751
752   return 0;
753 }
754
755
756 #ifdef SUNOS_NO_IFADDRS
757 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
758   *count = 0;
759   *addresses = NULL;
760   return UV_ENOSYS;
761 }
762 #else  /* SUNOS_NO_IFADDRS */
763 /*
764  * Inspired By:
765  * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
766  * http://www.pauliesworld.org/project/getmac.c
767  */
768 static int uv__set_phys_addr(uv_interface_address_t* address,
769                              struct ifaddrs* ent) {
770
771   struct sockaddr_dl* sa_addr;
772   int sockfd;
773   size_t i;
774   struct arpreq arpreq;
775
776   /* This appears to only work as root */
777   sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
778   memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
779   for (i = 0; i < sizeof(address->phys_addr); i++) {
780     /* Check that all bytes of phys_addr are zero. */
781     if (address->phys_addr[i] != 0)
782       return 0;
783   }
784   memset(&arpreq, 0, sizeof(arpreq));
785   if (address->address.address4.sin_family == AF_INET) {
786     struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa);
787     sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr;
788   } else if (address->address.address4.sin_family == AF_INET6) {
789     struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa);
790     memcpy(sin->sin6_addr.s6_addr,
791            address->address.address6.sin6_addr.s6_addr,
792            sizeof(address->address.address6.sin6_addr.s6_addr));
793   } else {
794     return 0;
795   }
796
797   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
798   if (sockfd < 0)
799     return UV__ERR(errno);
800
801   if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) {
802     uv__close(sockfd);
803     return UV__ERR(errno);
804   }
805   memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr));
806   uv__close(sockfd);
807   return 0;
808 }
809
810
811 static int uv__ifaddr_exclude(struct ifaddrs *ent) {
812   if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
813     return 1;
814   if (ent->ifa_addr == NULL)
815     return 1;
816   if (ent->ifa_addr->sa_family != AF_INET &&
817       ent->ifa_addr->sa_family != AF_INET6)
818     return 1;
819   return 0;
820 }
821
822 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
823   uv_interface_address_t* address;
824   struct ifaddrs* addrs;
825   struct ifaddrs* ent;
826
827   *count = 0;
828   *addresses = NULL;
829
830   if (getifaddrs(&addrs))
831     return UV__ERR(errno);
832
833   /* Count the number of interfaces */
834   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
835     if (uv__ifaddr_exclude(ent))
836       continue;
837     (*count)++;
838   }
839
840   if (*count == 0) {
841     freeifaddrs(addrs);
842     return 0;
843   }
844
845   *addresses = uv__malloc(*count * sizeof(**addresses));
846   if (!(*addresses)) {
847     freeifaddrs(addrs);
848     return UV_ENOMEM;
849   }
850
851   address = *addresses;
852
853   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
854     if (uv__ifaddr_exclude(ent))
855       continue;
856
857     address->name = uv__strdup(ent->ifa_name);
858
859     if (ent->ifa_addr->sa_family == AF_INET6) {
860       address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
861     } else {
862       address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
863     }
864
865     if (ent->ifa_netmask->sa_family == AF_INET6) {
866       address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
867     } else {
868       address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
869     }
870
871     address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
872                            (ent->ifa_flags & IFF_LOOPBACK));
873
874     uv__set_phys_addr(address, ent);
875     address++;
876   }
877
878   freeifaddrs(addrs);
879
880   return 0;
881 }
882 #endif  /* SUNOS_NO_IFADDRS */
883
884 void uv_free_interface_addresses(uv_interface_address_t* addresses,
885   int count) {
886   int i;
887
888   for (i = 0; i < count; i++) {
889     uv__free(addresses[i].name);
890   }
891
892   uv__free(addresses);
893 }
894
895
896 #if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L
897 size_t strnlen(const char* s, size_t maxlen) {
898   const char* end;
899   end = memchr(s, '\0', maxlen);
900   if (end == NULL)
901     return maxlen;
902   return end - s;
903 }
904 #endif