sunos.c 20 KB

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