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