#include "uv.h"
#include "internal.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <utmp.h>
#include <libgen.h>
#include <sys/protosw.h>
#include <libperfstat.h>
#include <procinfo.h>
#include <sys/proc.h>
#include <sys/procfs.h>
#include <sys/poll.h>
#include <sys/pollset.h>
#include <ctype.h>
#ifdef HAVE_SYS_AHAFS_EVPRODS_H
#include <sys/ahafs_evProds.h>
#endif
#include <sys/mntctl.h>
#include <sys/vmount.h>
#include <limits.h>
#include <strings.h>
#include <sys/vnode.h>
#define RDWR_BUF_SIZE 4096
#define EQ(a,b) (strcmp(a,b) == 0)
char* original_exepath = NULL;
uv_mutex_t process_title_mutex;
uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static void* args_mem = NULL;
static char** process_argv = NULL;
static int process_argc = 0;
static char* process_title_ptr = NULL;
void init_process_title_mutex_once(void) {
uv_mutex_init(&process_title_mutex);
}
int uv__platform_loop_init(uv_loop_t* loop) {
loop->fs_fd = -1;
loop->backend_fd = pollset_create(-1);
if (loop->backend_fd == -1)
return -1;
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->fs_fd != -1) {
uv__close(loop->fs_fd);
loop->fs_fd = -1;
}
if (loop->backend_fd != -1) {
pollset_destroy(loop->backend_fd);
loop->backend_fd = -1;
}
}
int uv__io_fork(uv_loop_t* loop) {
uv__platform_loop_delete(loop);
return uv__platform_loop_init(loop);
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct poll_ctl pc;
pc.events = POLLIN;
pc.cmd = PS_MOD;
pc.fd = fd;
if (pollset_ctl(loop->backend_fd, &pc, 1))
return UV__ERR(errno);
pc.cmd = PS_DELETE;
if (pollset_ctl(loop->backend_fd, &pc, 1))
abort();
return 0;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
struct pollfd events[1024];
struct pollfd pqry;
struct pollfd* pe;
struct poll_ctl pc;
QUEUE* q;
uv__io_t* w;
uint64_t base;
uint64_t diff;
int have_signals;
int nevents;
int count;
int nfds;
int i;
int rc;
int add_failed;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
pc.events = w->pevents;
pc.fd = w->fd;
add_failed = 0;
if (w->events == 0) {
pc.cmd = PS_ADD;
if (pollset_ctl(loop->backend_fd, &pc, 1)) {
if (errno != EINVAL) {
assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
abort();
}
pqry.fd = pc.fd;
rc = pollset_query(loop->backend_fd, &pqry);
switch (rc) {
case -1:
assert(0 && "Failed to query pollset for file descriptor");
abort();
case 0:
assert(0 && "Pollset does not contain file descriptor");
abort();
}
add_failed = 1;
}
}
if (w->events != 0 || add_failed) {
pc.cmd = PS_DELETE;
if (pollset_ctl(loop->backend_fd, &pc, 1)) {
assert(0 && "Failed to delete file descriptor (pc.fd) from pollset");
abort();
}
pc.cmd = PS_ADD;
if (pollset_ctl(loop->backend_fd, &pc, 1)) {
assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
abort();
}
}
w->events = w->pevents;
}
assert(timeout >= -1);
base = loop->time;
count = 48;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (;;) {
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
nfds = pollset_poll(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout);
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
if (timeout == -1)
continue;
if (timeout > 0)
goto update_timeout;
}
assert(timeout != -1);
return;
}
if (nfds == -1) {
if (errno != EINTR) {
abort();
}
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
goto update_timeout;
}
have_signals = 0;
nevents = 0;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
pe = events + i;
pc.cmd = PS_DELETE;
pc.fd = pe->fd;
if (pc.fd == -1)
continue;
assert(pc.fd >= 0);
assert((unsigned) pc.fd < loop->nwatchers);
w = loop->watchers[pc.fd];
if (w == NULL) {
pollset_ctl(loop->backend_fd, &pc, 1);
continue;
}
if (w == &loop->signal_io_watcher) {
have_signals = 1;
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->revents);
}
nevents++;
}
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (have_signals != 0)
return;
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
timeout = 0;
continue;
}
return;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
diff = loop->time - base;
if (diff >= (uint64_t) timeout)
return;
timeout -= diff;
}
}
uint64_t uv_get_free_memory(void) {
perfstat_memory_total_t mem_total;
int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
if (result == -1) {
return 0;
}
return mem_total.real_free * 4096;
}
uint64_t uv_get_total_memory(void) {
perfstat_memory_total_t mem_total;
int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
if (result == -1) {
return 0;
}
return mem_total.real_total * 4096;
}
uint64_t uv_get_constrained_memory(void) {
return 0;
}
void uv_loadavg(double avg[3]) {
perfstat_cpu_total_t ps_total;
int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
if (result == -1) {
avg[0] = 0.; avg[1] = 0.; avg[2] = 0.;
return;
}
avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS);
avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS);
avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS);
}
#ifdef HAVE_SYS_AHAFS_EVPRODS_H
static char* uv__rawname(const char* cp, char (*dst)[FILENAME_MAX+1]) {
char* dp;
dp = rindex(cp, '/');
if (dp == 0)
return 0;
snprintf(*dst, sizeof(*dst), "%.*s/r%s", (int) (dp - cp), cp, dp + 1);
return *dst;
}
static int uv__path_is_a_directory(char* filename) {
struct stat statbuf;
if (stat(filename, &statbuf) < 0)
return -1;
if (statbuf.st_type == VDIR)
return 0;
return -1;
}
static int uv__is_ahafs_mounted(void){
char rawbuf[FILENAME_MAX+1];
int rv, i = 2;
struct vmount *p;
int size_multiplier = 10;
size_t siz = sizeof(struct vmount)*size_multiplier;
struct vmount *vmt;
const char *dev = "/aha";
char *obj, *stub;
p = uv__malloc(siz);
if (p == NULL)
return UV__ERR(errno);
rv = mntctl(MCTL_QUERY, siz, (char*)p);
if (rv < 0)
return UV__ERR(errno);
if (rv == 0) {
siz = *(int*)p;
uv__free(p);
p = uv__malloc(siz);
if (p == NULL)
return UV__ERR(errno);
rv = mntctl(MCTL_QUERY, siz, (char*)p);
if (rv < 0)
return UV__ERR(errno);
}
for(vmt = p, i = 0; i < rv; i++) {
obj = vmt2dataptr(vmt, VMT_OBJECT);
stub = vmt2dataptr(vmt, VMT_STUB);
if (EQ(obj, dev) || EQ(uv__rawname(obj, &rawbuf), dev) || EQ(stub, dev)) {
uv__free(p);
return 0;
}
vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length);
}
return -1;
}
static int uv__makedir_p(const char *dir) {
char tmp[256];
char *p = NULL;
size_t len;
int err;
uv__strscpy(tmp, dir, sizeof(tmp));
len = strlen(tmp);
if (tmp[len - 1] == '/')
tmp[len - 1] = 0;
for (p = tmp + 1; *p; p++) {
if (*p == '/') {
*p = 0;
err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (err != 0 && errno != EEXIST)
return err;
*p = '/';
}
}
return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
}
static int uv__make_subdirs_p(const char *filename) {
char cmd[2048];
char *p;
int rc = 0;
p = strrchr(filename, '/');
if (p == NULL)
return 0;
if (uv__path_is_a_directory((char*)filename) == 0) {
sprintf(cmd, "/aha/fs/modDir.monFactory");
} else {
sprintf(cmd, "/aha/fs/modFile.monFactory");
}
strncat(cmd, filename, (p - filename));
rc = uv__makedir_p(cmd);
if (rc == -1 && errno != EEXIST){
return UV__ERR(errno);
}
return rc;
}
static int uv__setup_ahafs(const char* filename, int *fd) {
int rc = 0;
char mon_file_write_string[RDWR_BUF_SIZE];
char mon_file[PATH_MAX];
int file_is_directory = 0;
file_is_directory = uv__path_is_a_directory((char*)filename);
if (file_is_directory == 0)
sprintf(mon_file, "/aha/fs/modDir.monFactory");
else
sprintf(mon_file, "/aha/fs/modFile.monFactory");
if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX)
return UV_ENAMETOOLONG;
rc = uv__make_subdirs_p(filename);
if (rc == -1 && errno != EEXIST)
return rc;
strcat(mon_file, filename);
strcat(mon_file, ".mon");
*fd = 0; errno = 0;
*fd = open(mon_file, O_CREAT|O_RDWR);
if (*fd < 0)
return UV__ERR(errno);
if (file_is_directory == 0)
sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2");
else
sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
if (rc < 0 && errno != EBUSY)
return UV__ERR(errno);
return 0;
}
static int uv__skip_lines(char **p, int n) {
int lines = 0;
while(n > 0) {
*p = strchr(*p, '\n');
if (!p)
return lines;
(*p)++;
n--;
lines++;
}
return lines;
}
static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) {
int evp_rc, i;
char *p;
char filename[PATH_MAX];
p = buf;
*events = 0;
for(i = 0; i < PATH_MAX; i++) {
filename[i] = 0;
}
i = 0;
if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) {
assert(0 && "Buffer wrap detected, Some event occurrences lost!");
return 0;
}
if (uv__skip_lines(&p, 9) != 9)
return -1;
if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) {
if (uv__path_is_a_directory(handle->path) == 0) {
if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) {
*events = UV_RENAME;
handle->dir_filename = NULL;
} else {
*events = UV_CHANGE;
if (uv__skip_lines(&p, 1) != 1)
return -1;
if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) {
handle->dir_filename = uv__strdup((const char*)&filename);
} else
return -1;
}
} else {
if (evp_rc == AHAFS_MODFILE_RENAME)
*events = UV_RENAME;
else
*events = UV_CHANGE;
}
}
else
return -1;
return 0;
}
static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) {
char result_data[RDWR_BUF_SIZE];
int bytes, rc = 0;
uv_fs_event_t* handle;
int events = 0;
char fname[PATH_MAX];
char *p;
handle = container_of(event_watch, uv_fs_event_t, event_watcher);
bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file");
if(bytes == 0)
return;
if(bytes > 0)
rc = uv__parse_data(result_data, &events, handle);
if (rc == -1)
return;
if (uv__path_is_a_directory(handle->path) == 0) {
p = handle->dir_filename;
} else {
p = strrchr(handle->path, '/');
if (p == NULL)
p = handle->path;
else
p++;
}
uv__strscpy(fname, p, sizeof(fname));
handle->cb(handle, fname, events, 0);
}
#endif
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
#ifdef HAVE_SYS_AHAFS_EVPRODS_H
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
#else
return UV_ENOSYS;
#endif
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
const char* filename,
unsigned int flags) {
#ifdef HAVE_SYS_AHAFS_EVPRODS_H
int fd, rc, str_offset = 0;
char cwd[PATH_MAX];
char absolute_path[PATH_MAX];
char readlink_cwd[PATH_MAX];
struct timeval zt;
fd_set pollfd;
if (filename[0] == '\0') {
return UV_ENOENT;
}
else if (filename[0] == '/') {
uv__strscpy(absolute_path, filename, sizeof(absolute_path));
} else {
snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid());
rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1);
if (rc < 0)
return rc;
readlink_cwd[rc] = '\0';
if (filename[0] == '.' && filename[1] == '/')
str_offset = 2;
snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd,
filename + str_offset);
}
if (uv__is_ahafs_mounted() < 0)
return UV_ENOSYS;
rc = uv__setup_ahafs((const char *)absolute_path, &fd);
if (rc != 0)
return rc;
uv__handle_start(handle);
uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
handle->path = uv__strdup(filename);
handle->cb = cb;
handle->dir_filename = NULL;
uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
do {
memset(&zt, 0, sizeof(zt));
FD_ZERO(&pollfd);
FD_SET(fd, &pollfd);
rc = select(fd + 1, &pollfd, NULL, NULL, &zt);
} while (rc == -1 && errno == EINTR);
return 0;
#else
return UV_ENOSYS;
#endif
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
#ifdef HAVE_SYS_AHAFS_EVPRODS_H
if (!uv__is_active(handle))
return 0;
uv__io_close(handle->loop, &handle->event_watcher);
uv__handle_stop(handle);
if (uv__path_is_a_directory(handle->path) == 0) {
uv__free(handle->dir_filename);
handle->dir_filename = NULL;
}
uv__free(handle->path);
handle->path = NULL;
uv__close(handle->event_watcher.fd);
handle->event_watcher.fd = -1;
return 0;
#else
return UV_ENOSYS;
#endif
}
void uv__fs_event_close(uv_fs_event_t* handle) {
#ifdef HAVE_SYS_AHAFS_EVPRODS_H
uv_fs_event_stop(handle);
#else
UNREACHABLE();
#endif
}
char** uv_setup_args(int argc, char** argv) {
char exepath[UV__PATH_MAX];
char** new_argv;
size_t size;
char* s;
int i;
if (argc <= 0)
return argv;
process_argv = argv;
process_argc = argc;
size = sizeof(exepath);
if (uv__search_path(argv[0], exepath, &size) == 0) {
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
original_exepath = uv__strdup(exepath);
uv_mutex_unlock(&process_title_mutex);
}
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
size += (argc + 1) * sizeof(char*);
new_argv = uv__malloc(size);
if (new_argv == NULL)
return argv;
args_mem = new_argv;
s = (char*) &new_argv[argc + 1];
for (i = 0; i < argc; i++) {
size = strlen(argv[i]) + 1;
memcpy(s, argv[i], size);
new_argv[i] = s;
s += size;
}
new_argv[i] = NULL;
return new_argv;
}
int uv_set_process_title(const char* title) {
char* new_title;
if (process_argv == NULL || args_mem == NULL)
return UV_ENOBUFS;
new_title = uv__strdup(title);
if (new_title == NULL)
return UV_ENOMEM;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
if (process_title_ptr != NULL)
uv__free(process_title_ptr);
process_title_ptr = new_title;
process_argv[0] = process_title_ptr;
if (process_argc > 1)
process_argv[1] = NULL;
uv_mutex_unlock(&process_title_mutex);
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
if (buffer == NULL || size == 0)
return UV_EINVAL;
if (process_argv == NULL)
return UV_ENOBUFS;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
len = strlen(process_argv[0]);
if (size <= len) {
uv_mutex_unlock(&process_title_mutex);
return UV_ENOBUFS;
}
memcpy(buffer, process_argv[0], len);
buffer[len] = '\0';
uv_mutex_unlock(&process_title_mutex);
return 0;
}
void uv__process_title_cleanup(void) {
uv__free(args_mem);
args_mem = NULL;
}
int uv_resident_set_memory(size_t* rss) {
char pp[64];
psinfo_t psinfo;
int err;
int fd;
snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
fd = open(pp, O_RDONLY);
if (fd == -1)
return UV__ERR(errno);
err = UV_EINVAL;
if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
*rss = (size_t)psinfo.pr_rssize * 1024;
err = 0;
}
uv__close(fd);
return err;
}
int uv_uptime(double* uptime) {
struct utmp *utmp_buf;
size_t entries = 0;
time_t boot_time;
boot_time = 0;
utmpname(UTMP_FILE);
setutent();
while ((utmp_buf = getutent()) != NULL) {
if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS)
++entries;
if (utmp_buf->ut_type == BOOT_TIME)
boot_time = utmp_buf->ut_time;
}
endutent();
if (boot_time == 0)
return UV_ENOSYS;
*uptime = time(NULL) - boot_time;
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
perfstat_cpu_total_t ps_total;
perfstat_cpu_t* ps_cpus;
perfstat_id_t cpu_id;
int result, ncpus, idx = 0;
result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
if (result == -1) {
return UV_ENOSYS;
}
ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
if (result == -1) {
return UV_ENOSYS;
}
ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t));
if (!ps_cpus) {
return UV_ENOMEM;
}
uv__strscpy(cpu_id.name, FIRST_CPU, sizeof(cpu_id.name));
result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
if (result == -1) {
uv__free(ps_cpus);
return UV_ENOSYS;
}
*cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t));
if (!*cpu_infos) {
uv__free(ps_cpus);
return UV_ENOMEM;
}
*count = ncpus;
cpu_info = *cpu_infos;
while (idx < ncpus) {
cpu_info->speed = (int)(ps_total.processorHZ / 1000000);
cpu_info->model = uv__strdup(ps_total.description);
cpu_info->cpu_times.user = ps_cpus[idx].user;
cpu_info->cpu_times.sys = ps_cpus[idx].sys;
cpu_info->cpu_times.idle = ps_cpus[idx].idle;
cpu_info->cpu_times.irq = ps_cpus[idx].wait;
cpu_info->cpu_times.nice = 0;
cpu_info++;
idx++;
}
uv__free(ps_cpus);
return 0;
}
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
int sockfd, sock6fd, inet6, i, r, size = 1;
struct ifconf ifc;
struct ifreq *ifr, *p, flg;
struct in6_ifreq if6;
struct sockaddr_dl* sa_addr;
ifc.ifc_req = NULL;
sock6fd = -1;
r = 0;
*count = 0;
*addresses = NULL;
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
r = UV__ERR(errno);
goto cleanup;
}
if (0 > (sock6fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP))) {
r = UV__ERR(errno);
goto cleanup;
}
if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
r = UV__ERR(errno);
goto cleanup;
}
ifc.ifc_req = (struct ifreq*)uv__malloc(size);
if (ifc.ifc_req == NULL) {
r = UV_ENOMEM;
goto cleanup;
}
ifc.ifc_len = size;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
r = UV__ERR(errno);
goto cleanup;
}
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
r = UV__ERR(errno);
goto cleanup;
}
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
(*count)++;
}
if (*count == 0)
goto cleanup;
*addresses = uv__calloc(*count, sizeof(**addresses));
if (!(*addresses)) {
r = UV_ENOMEM;
goto cleanup;
}
address = *addresses;
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
inet6 = (p->ifr_addr.sa_family == AF_INET6);
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1)
goto syserror;
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
address->name = uv__strdup(p->ifr_name);
if (inet6)
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
else
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
if (inet6) {
memset(&if6, 0, sizeof(if6));
r = uv__strscpy(if6.ifr_name, p->ifr_name, sizeof(if6.ifr_name));
if (r == UV_E2BIG)
goto cleanup;
r = 0;
memcpy(&if6.ifr_Addr, &p->ifr_addr, sizeof(if6.ifr_Addr));
if (ioctl(sock6fd, SIOCGIFNETMASK6, &if6) == -1)
goto syserror;
address->netmask.netmask6 = *((struct sockaddr_in6*) &if6.ifr_Addr);
address->netmask.netmask6.sin6_family = AF_INET6;
} else {
if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1)
goto syserror;
address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
address->netmask.netmask4.sin_family = AF_INET;
}
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
address++;
}
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (p->ifr_addr.sa_family != AF_LINK)
continue;
address = *addresses;
for (i = 0; i < *count; i++) {
if (strcmp(address->name, p->ifr_name) == 0) {
sa_addr = (struct sockaddr_dl*) &p->ifr_addr;
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
}
address++;
}
}
#undef ADDR_SIZE
goto cleanup;
syserror:
uv_free_interface_addresses(*addresses, *count);
*addresses = NULL;
*count = 0;
r = UV_ENOSYS;
cleanup:
if (sockfd != -1)
uv__close(sockfd);
if (sock6fd != -1)
uv__close(sock6fd);
uv__free(ifc.ifc_req);
return r;
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; ++i) {
uv__free(addresses[i].name);
}
uv__free(addresses);
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct pollfd* events;
uintptr_t i;
uintptr_t nfds;
struct poll_ctl pc;
assert(loop->watchers != NULL);
assert(fd >= 0);
events = (struct pollfd*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events != NULL)
for (i = 0; i < nfds; i++)
if ((int) events[i].fd == fd)
events[i].fd = -1;
pc.events = 0;
pc.cmd = PS_DELETE;
pc.fd = fd;
if(loop->backend_fd >= 0)
pollset_ctl(loop->backend_fd, &pc, 1);
}