sunos.c 20 KB

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