void uv__loop_close(uv_loop_t* loop) { uv__signal_loop_cleanup(loop); uv__platform_loop_delete(loop); uv__async_stop(loop); if (loop->emfile_fd != -1) { uv__close(loop->emfile_fd); loop->emfile_fd = -1; } if (loop->backend_fd != -1) { uv__close(loop->backend_fd); loop->backend_fd = -1; } uv_mutex_lock(&loop->wq_mutex); assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); assert(!uv__has_active_reqs(loop)); uv_mutex_unlock(&loop->wq_mutex); uv_mutex_destroy(&loop->wq_mutex); /* * Note that all thread pool stuff is finished at this point and * it is safe to just destroy rw lock */ uv_rwlock_destroy(&loop->cloexec_lock); #if 0 assert(QUEUE_EMPTY(&loop->pending_queue)); assert(QUEUE_EMPTY(&loop->watcher_queue)); assert(loop->nfds == 0); #endif uv__free(loop->watchers); loop->watchers = NULL; loop->nwatchers = 0; }
int uv_set_process_title(const char* title) { int oid[4]; char* new_title; new_title = uv__strdup(title); if (process_title == NULL) return -ENOMEM; uv__free(process_title); process_title = new_title; oid[0] = CTL_KERN; oid[1] = KERN_PROC; oid[2] = KERN_PROC_ARGS; oid[3] = getpid(); sysctl(oid, ARRAY_SIZE(oid), NULL, NULL, process_title, strlen(process_title) + 1); return 0; }
int uv_set_process_title(const char* title) { char* new_title; /* We cannot free this pointer when libuv shuts down, * the process may still be using it. */ new_title = uv__strdup(title); if (new_title == NULL) return -ENOMEM; /* If this is the first time this is set, * don't free and set argv[1] to NULL. */ 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; return 0; }
/* * Called from uv_run when complete. Call user specified callback * then free returned addrinfo * Returned addrinfo strings are converted from UTF-16 to UTF-8. * * To minimize allocation we calculate total size required, * and copy all structs and referenced strings into the one block. * Each size calculation is adjusted to avoid unaligned pointers. */ static void uv__getaddrinfo_done(struct uv__work* w, int status) { uv_getaddrinfo_t* req; int addrinfo_len = 0; int name_len = 0; size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); struct addrinfoW* addrinfow_ptr; struct addrinfo* addrinfo_ptr; char* alloc_ptr = NULL; char* cur_ptr = NULL; req = container_of(w, uv_getaddrinfo_t, work_req); /* release input parameter memory */ uv__free(req->alloc); req->alloc = NULL; if (status == UV_ECANCELED) { assert(req->retcode == 0); req->retcode = UV_EAI_CANCELED; goto complete; } if (req->retcode == 0) { /* Convert addrinfoW to addrinfo. First calculate required length. */ addrinfow_ptr = req->addrinfow; while (addrinfow_ptr != NULL) { addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); if (addrinfow_ptr->ai_canonname != NULL) { name_len = WideCharToMultiByte(CP_UTF8, 0, addrinfow_ptr->ai_canonname, -1, NULL, 0, NULL, NULL); if (name_len == 0) { req->retcode = uv_translate_sys_error(GetLastError()); goto complete; } addrinfo_len += ALIGNED_SIZE(name_len); } addrinfow_ptr = addrinfow_ptr->ai_next; } /* allocate memory for addrinfo results */ alloc_ptr = (char*)uv__malloc(addrinfo_len); /* do conversions */ if (alloc_ptr != NULL) { cur_ptr = alloc_ptr; addrinfow_ptr = req->addrinfow; while (addrinfow_ptr != NULL) { /* copy addrinfo struct data */ assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len); addrinfo_ptr = (struct addrinfo*)cur_ptr; addrinfo_ptr->ai_family = addrinfow_ptr->ai_family; addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype; addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol; addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags; addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen; addrinfo_ptr->ai_canonname = NULL; addrinfo_ptr->ai_addr = NULL; addrinfo_ptr->ai_next = NULL; cur_ptr += addrinfo_struct_len; /* copy sockaddr */ if (addrinfo_ptr->ai_addrlen > 0) { assert(cur_ptr + addrinfo_ptr->ai_addrlen <= alloc_ptr + addrinfo_len); memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen); addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr; cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen); } /* convert canonical name to UTF-8 */ if (addrinfow_ptr->ai_canonname != NULL) { name_len = WideCharToMultiByte(CP_UTF8, 0, addrinfow_ptr->ai_canonname, -1, NULL, 0, NULL, NULL); assert(name_len > 0); assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); name_len = WideCharToMultiByte(CP_UTF8, 0, addrinfow_ptr->ai_canonname, -1, cur_ptr, name_len, NULL, NULL); assert(name_len > 0); addrinfo_ptr->ai_canonname = cur_ptr; cur_ptr += ALIGNED_SIZE(name_len); } assert(cur_ptr <= alloc_ptr + addrinfo_len); /* set next ptr */ addrinfow_ptr = addrinfow_ptr->ai_next; if (addrinfow_ptr != NULL) { addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr; } } req->addrinfo = (struct addrinfo*)alloc_ptr; } else { req->retcode = UV_EAI_MEMORY; } } /* return memory to system */ if (req->addrinfow != NULL) { FreeAddrInfoW(req->addrinfow); req->addrinfow = NULL; } complete: uv__req_unregister(req->loop, req); /* finally do callback with converted result */ if (req->getaddrinfo_cb) req->getaddrinfo_cb(req, req->retcode, req->addrinfo); }
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { int err; unsigned int i; uv_tcp_accept_t* req; if (handle->flags & UV_HANDLE_CONNECTION && handle->stream.conn.shutdown_req != NULL && handle->stream.conn.write_reqs_pending == 0) { UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); err = 0; if (handle->flags & UV_HANDLE_CLOSING) { err = ERROR_OPERATION_ABORTED; } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) { err = WSAGetLastError(); } if (handle->stream.conn.shutdown_req->cb) { handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, uv_translate_sys_error(err)); } handle->stream.conn.shutdown_req = NULL; DECREASE_PENDING_REQ_COUNT(handle); return; } if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { closesocket(handle->socket); handle->socket = INVALID_SOCKET; handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; } if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) { if (handle->flags & UV_HANDLE_EMULATE_IOCP) { for (i = 0; i < uv_simultaneous_server_accepts; i++) { req = &handle->tcp.serv.accept_reqs[i]; if (req->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(req->wait_handle); req->wait_handle = INVALID_HANDLE_VALUE; } if (req->event_handle) { CloseHandle(req->event_handle); req->event_handle = NULL; } } } uv__free(handle->tcp.serv.accept_reqs); handle->tcp.serv.accept_reqs = NULL; } if (handle->flags & UV_HANDLE_CONNECTION && handle->flags & UV_HANDLE_EMULATE_IOCP) { if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(handle->read_req.wait_handle); handle->read_req.wait_handle = INVALID_HANDLE_VALUE; } if (handle->read_req.event_handle) { CloseHandle(handle->read_req.event_handle); handle->read_req.event_handle = NULL; } } uv__handle_close(handle); loop->active_tcp_streams--; } }
int uv_spawn(uv_loop_t* loop, uv_process_t* process, const uv_process_options_t* options) { int i; int err = 0; WCHAR* path = NULL, *alloc_path = NULL; BOOL result; WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; DWORD process_flags; uv_process_init(loop, process); process->exit_cb = options->exit_cb; if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { return UV_ENOTSUP; } if (options->file == NULL || options->args == NULL) { return UV_EINVAL; } assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); err = uv_utf8_to_utf16_alloc(options->file, &application); if (err) goto done; err = make_program_args( options->args, options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, &arguments); if (err) goto done; if (options->env) { err = make_program_env(options->env, &env); if (err) goto done; } if (options->cwd) { /* Explicit cwd */ err = uv_utf8_to_utf16_alloc(options->cwd, &cwd); if (err) goto done; } else { /* Inherit cwd */ DWORD cwd_len, r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { err = GetLastError(); goto done; } cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR)); if (cwd == NULL) { err = ERROR_OUTOFMEMORY; goto done; } r = GetCurrentDirectoryW(cwd_len, cwd); if (r == 0 || r >= cwd_len) { err = GetLastError(); goto done; } } /* Get PATH environment variable. */ path = find_path(env); if (path == NULL) { DWORD path_len, r; path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); if (path_len == 0) { err = GetLastError(); goto done; } alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR)); if (alloc_path == NULL) { err = ERROR_OUTOFMEMORY; goto done; } path = alloc_path; r = GetEnvironmentVariableW(L"PATH", path, path_len); if (r == 0 || r >= path_len) { err = GetLastError(); goto done; } } err = uv__stdio_create(loop, options, &process->child_stdio_buffer); if (err) goto done; application_path = search_path(application, cwd, path); if (application_path == NULL) { /* Not found. */ err = ERROR_FILE_NOT_FOUND; goto done; } startup.cb = sizeof(startup); startup.lpReserved = NULL; startup.lpDesktop = NULL; startup.lpTitle = NULL; startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); startup.lpReserved2 = (BYTE*) process->child_stdio_buffer; startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); if (options->flags & UV_PROCESS_WINDOWS_HIDE) { /* Use SW_HIDE to avoid any potential process window. */ startup.wShowWindow = SW_HIDE; } else { startup.wShowWindow = SW_SHOWDEFAULT; } process_flags = CREATE_UNICODE_ENVIRONMENT; if (options->flags & UV_PROCESS_DETACHED) { /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That * means that libuv might not let you create a fully daemonized process * when run under job control. However the type of job control that libuv * itself creates doesn't trickle down to subprocesses so they can still * daemonize. * * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the * CreateProcess call fail if we're under job control that doesn't allow * breakaway. */ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; } if (!CreateProcessW(application_path, arguments, NULL, NULL, 1, process_flags, env, cwd, &startup, &info)) { /* CreateProcessW failed. */ err = GetLastError(); goto done; } /* Spawn succeeded */ /* Beyond this point, failure is reported asynchronously. */ process->process_handle = info.hProcess; process->pid = info.dwProcessId; /* If the process isn't spawned as detached, assign to the global job */ /* object so windows will kill it when the parent process dies. */ if (!(options->flags & UV_PROCESS_DETACHED)) { uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) { /* AssignProcessToJobObject might fail if this process is under job * control and the job doesn't have the * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version * that doesn't support nested jobs. * * When that happens we just swallow the error and continue without * establishing a kill-child-on-parent-exit relationship, otherwise * there would be no way for libuv applications run under job control * to spawn processes at all. */ DWORD err = GetLastError(); if (err != ERROR_ACCESS_DENIED) uv_fatal_error(err, "AssignProcessToJobObject"); } } /* Set IPC pid to all IPC pipes. */ for (i = 0; i < options->stdio_count; i++) { const uv_stdio_container_t* fdopt = &options->stdio[i]; if (fdopt->flags & UV_CREATE_PIPE && fdopt->data.stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) fdopt->data.stream)->ipc) { ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId; } } /* Setup notifications for when the child process exits. */ result = RegisterWaitForSingleObject(&process->wait_handle, process->process_handle, exit_wait_callback, (void*)process, INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); if (!result) { uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); } CloseHandle(info.hThread); assert(!err); /* Make the handle active. It will remain active until the exit callback */ /* is made or the handle is closed, whichever happens first. */ uv__handle_start(process); /* Cleanup, whether we succeeded or failed. */ done: uv__free(application); uv__free(application_path); uv__free(arguments); uv__free(cwd); uv__free(env); uv__free(alloc_path); if (process->child_stdio_buffer != NULL) { /* Clean up child stdio handles. */ uv__stdio_destroy(process->child_stdio_buffer); process->child_stdio_buffer = NULL; } return uv_translate_sys_error(err); }
int uv_spawn(uv_loop_t* loop, uv_process_t* process, const uv_process_options_t* options) { int signal_pipe[2] = { -1, -1 }; int (*pipes)[2]; int stdio_count; ssize_t r; pid_t pid; int err; int exec_errorno; int i; int status; assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); QUEUE_INIT(&process->queue); stdio_count = options->stdio_count; if (stdio_count < 3) stdio_count = 3; err = -ENOMEM; pipes = uv__malloc(stdio_count * sizeof(*pipes)); if (pipes == NULL) goto error; for (i = 0; i < stdio_count; i++) { pipes[i][0] = -1; pipes[i][1] = -1; } for (i = 0; i < options->stdio_count; i++) { err = uv__process_init_stdio(options->stdio + i, pipes[i]); if (err) goto error; } /* This pipe is used by the parent to wait until * the child has called `execve()`. We need this * to avoid the following race condition: * * if ((pid = fork()) > 0) { * kill(pid, SIGTERM); * } * else if (pid == 0) { * execve("/bin/cat", argp, envp); * } * * The parent sends a signal immediately after forking. * Since the child may not have called `execve()` yet, * there is no telling what process receives the signal, * our fork or /bin/cat. * * To avoid ambiguity, we create a pipe with both ends * marked close-on-exec. Then, after the call to `fork()`, * the parent polls the read end until it EOFs or errors with EPIPE. */ err = uv__make_pipe(signal_pipe, 0); if (err) goto error; uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); /* Acquire write lock to prevent opening new fds in worker threads */ uv_rwlock_wrlock(&loop->cloexec_lock); pid = fork(); if (pid == -1) { err = -errno; uv_rwlock_wrunlock(&loop->cloexec_lock); uv__close(signal_pipe[0]); uv__close(signal_pipe[1]); goto error; } if (pid == 0) { uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); abort(); } /* Release lock in parent process */ uv_rwlock_wrunlock(&loop->cloexec_lock); uv__close(signal_pipe[1]); process->status = 0; exec_errorno = 0; do r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); while (r == -1 && errno == EINTR); if (r == 0) ; /* okay, EOF */ else if (r == sizeof(exec_errorno)) { do err = waitpid(pid, &status, 0); /* okay, read errorno */ while (err == -1 && errno == EINTR); assert(err == pid); } else if (r == -1 && errno == EPIPE) { do err = waitpid(pid, &status, 0); /* okay, got EPIPE */ while (err == -1 && errno == EINTR); assert(err == pid); } else abort(); uv__close(signal_pipe[0]); for (i = 0; i < options->stdio_count; i++) { err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0); if (err == 0) continue; while (i--) uv__process_close_stream(options->stdio + i); goto error; } /* Only activate this handle if exec() happened successfully */ if (exec_errorno == 0) { QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); uv__handle_start(process); } process->pid = pid; process->exit_cb = options->exit_cb; uv__free(pipes); return exec_errorno; error: if (pipes != NULL) { for (i = 0; i < stdio_count; i++) { if (i < options->stdio_count) if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) continue; if (pipes[i][0] != -1) close(pipes[i][0]); if (pipes[i][1] != -1) close(pipes[i][1]); } uv__free(pipes); } return err; }
int uv_uptime(double* uptime) { BYTE stack_buffer[4096]; BYTE* malloced_buffer = NULL; BYTE* buffer = (BYTE*) stack_buffer; size_t buffer_size = sizeof(stack_buffer); DWORD data_size; PERF_DATA_BLOCK* data_block; PERF_OBJECT_TYPE* object_type; PERF_COUNTER_DEFINITION* counter_definition; DWORD i; for (;;) { LONG result; data_size = (DWORD) buffer_size; result = RegQueryValueExW(HKEY_PERFORMANCE_DATA, L"2", NULL, NULL, buffer, &data_size); if (result == ERROR_SUCCESS) { break; } else if (result != ERROR_MORE_DATA) { *uptime = 0; return uv_translate_sys_error(result); } uv__free(malloced_buffer); buffer_size *= 2; /* Don't let the buffer grow infinitely. */ if (buffer_size > 1 << 20) { goto internalError; } buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size); if (malloced_buffer == NULL) { *uptime = 0; return UV_ENOMEM; } } if (data_size < sizeof(*data_block)) goto internalError; data_block = (PERF_DATA_BLOCK*) buffer; if (wmemcmp(data_block->Signature, L"PERF", 4) != 0) goto internalError; if (data_size < data_block->HeaderLength + sizeof(*object_type)) goto internalError; object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength); if (object_type->NumInstances != PERF_NO_INSTANCES) goto internalError; counter_definition = (PERF_COUNTER_DEFINITION*) (buffer + data_block->HeaderLength + object_type->HeaderLength); for (i = 0; i < object_type->NumCounters; i++) { if ((BYTE*) counter_definition + sizeof(*counter_definition) > buffer + data_size) { break; } if (counter_definition->CounterNameTitleIndex == 674 && counter_definition->CounterSize == sizeof(uint64_t)) { if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size || !(counter_definition->CounterType & PERF_OBJECT_TIMER)) { goto internalError; } else { BYTE* address = (BYTE*) object_type + object_type->DefinitionLength + counter_definition->CounterOffset; uint64_t value = *((uint64_t*) address); *uptime = (double) (object_type->PerfTime.QuadPart - value) / (double) object_type->PerfFreq.QuadPart; uv__free(malloced_buffer); return 0; } } counter_definition = (PERF_COUNTER_DEFINITION*) ((BYTE*) counter_definition + counter_definition->ByteLength); } /* If we get here, the uptime value was not found. */ uv__free(malloced_buffer); *uptime = 0; return UV_ENOSYS; internalError: uv__free(malloced_buffer); *uptime = 0; return UV_EIO; }
/* * We could use a static buffer for the path manipulations that we need outside * of the function, but this function could be called by multiple consumers and * we don't want to potentially create a race condition in the use of snprintf. * There is no direct way of getting the exe path in AIX - either through /procfs * or through some libc APIs. The below approach is to parse the argv[0]'s pattern * and use it in conjunction with PATH environment variable to craft one. */ int uv_exepath(char* buffer, size_t* size) { int res; char args[PATH_MAX]; char abspath[PATH_MAX]; size_t abspath_size; struct procsinfo pi; if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; pi.pi_pid = getpid(); res = getargs(&pi, sizeof(pi), args, sizeof(args)); if (res < 0) return UV_EINVAL; /* * Possibilities for args: * i) an absolute path such as: /home/user/myprojects/nodejs/node * ii) a relative path such as: ./node or ../myprojects/nodejs/node * iii) a bare filename such as "node", after exporting PATH variable * to its location. */ /* Case i) and ii) absolute or relative paths */ if (strchr(args, '/') != NULL) { if (realpath(args, abspath) != abspath) return UV__ERR(errno); abspath_size = strlen(abspath); *size -= 1; if (*size > abspath_size) *size = abspath_size; memcpy(buffer, abspath, *size); buffer[*size] = '\0'; return 0; } else { /* Case iii). Search PATH environment variable */ char trypath[PATH_MAX]; char *clonedpath = NULL; char *token = NULL; char *path = getenv("PATH"); if (path == NULL) return UV_EINVAL; clonedpath = uv__strdup(path); if (clonedpath == NULL) return UV_ENOMEM; token = strtok(clonedpath, ":"); while (token != NULL) { snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); if (realpath(trypath, abspath) == abspath) { /* Check the match is executable */ if (access(abspath, X_OK) == 0) { abspath_size = strlen(abspath); *size -= 1; if (*size > abspath_size) *size = abspath_size; memcpy(buffer, abspath, *size); buffer[*size] = '\0'; uv__free(clonedpath); return 0; } } token = strtok(NULL, ":"); } uv__free(clonedpath); /* Out of tokens (path entries), and no match found */ return UV_EINVAL; } }
int uv_set_process_title(const char* title) { if (process_title) uv__free(process_title); process_title = uv__strdup(title); setproctitle(title); return 0; }
static ssize_t uv__fs_read(uv_fs_t* req) { #if defined(__linux__) static int no_preadv; #endif ssize_t result; #if defined(_AIX) struct stat buf; if(fstat(req->file, &buf)) return -1; if(S_ISDIR(buf.st_mode)) { errno = EISDIR; return -1; } #endif /* defined(_AIX) */ if (req->off < 0) { if (req->nbufs == 1) result = read(req->file, req->bufs[0].base, req->bufs[0].len); else result = readv(req->file, (struct iovec*) req->bufs, req->nbufs); } else { if (req->nbufs == 1) { result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off); goto done; } #if HAVE_PREADV result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); #else # if defined(__linux__) if (no_preadv) retry: # endif { off_t nread; size_t index; nread = 0; index = 0; result = 1; do { if (req->bufs[index].len > 0) { result = pread(req->file, req->bufs[index].base, req->bufs[index].len, req->off + nread); if (result > 0) nread += result; } index++; } while (index < req->nbufs && result > 0); if (nread > 0) result = nread; } # if defined(__linux__) else { result = uv__preadv(req->file, (struct iovec*)req->bufs, req->nbufs, req->off); if (result == -1 && errno == ENOSYS) { no_preadv = 1; goto retry; } } # endif #endif } done: if (req->bufs != req->bufsml) uv__free(req->bufs); return result; }
static ssize_t uv__fs_readlink(uv_fs_t* req) { ssize_t maxlen; ssize_t len; char* buf; char* newbuf; #if defined(UV__FS_PATH_MAX_FALLBACK) /* We may not have a real PATH_MAX. Read size of link. */ struct stat st; int ret; ret = lstat(req->path, &st); if (ret != 0) return -1; if (!S_ISLNK(st.st_mode)) { errno = EINVAL; return -1; } maxlen = st.st_size; /* According to readlink(2) lstat can report st_size == 0 for some symlinks, such as those in /proc or /sys. */ if (maxlen == 0) maxlen = uv__fs_pathmax_size(req->path); #else maxlen = uv__fs_pathmax_size(req->path); #endif buf = uv__malloc(maxlen); if (buf == NULL) { errno = ENOMEM; return -1; } #if defined(__MVS__) len = os390_readlink(req->path, buf, maxlen); #else len = readlink(req->path, buf, maxlen); #endif if (len == -1) { uv__free(buf); return -1; } /* Uncommon case: resize to make room for the trailing nul byte. */ if (len == maxlen) { newbuf = uv__realloc(buf, len + 1); if (newbuf == NULL) { uv__free(buf); return -1; } buf = newbuf; } buf[len] = '\0'; req->ptr = buf; return 0; }
UV_DESTRUCTOR(static void free_args_mem(void)) { uv__free(args_mem); /* Keep valgrind happy. */ args_mem = NULL; }
int uv_loop_init(uv_loop_t* loop) { struct heap* timer_heap; int err; /* Initialize libuv itself first */ uv__once_init(); /* Create an I/O completion port */ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (loop->iocp == NULL) return uv_translate_sys_error(GetLastError()); /* To prevent uninitialized memory access, loop->time must be initialized * to zero before calling uv_update_time for the first time. */ loop->time = 0; uv_update_time(loop); QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->handle_queue); loop->active_reqs.count = 0; loop->active_handles = 0; loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap)); if (timer_heap == NULL) { err = UV_ENOMEM; goto fail_timers_alloc; } heap_init(timer_heap); loop->check_handles = NULL; loop->prepare_handles = NULL; loop->idle_handles = NULL; loop->next_prepare_handle = NULL; loop->next_check_handle = NULL; loop->next_idle_handle = NULL; memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); loop->active_tcp_streams = 0; loop->active_udp_streams = 0; loop->timer_counter = 0; loop->stop_flag = 0; err = uv_mutex_init(&loop->wq_mutex); if (err) goto fail_mutex_init; err = uv_async_init(loop, &loop->wq_async, uv__work_done); if (err) goto fail_async_init; uv__handle_unref(&loop->wq_async); loop->wq_async.flags |= UV_HANDLE_INTERNAL; err = uv__loops_add(loop); if (err) goto fail_async_init; return 0; fail_async_init: uv_mutex_destroy(&loop->wq_mutex); fail_mutex_init: uv__free(timer_heap); loop->timer_heap = NULL; fail_timers_alloc: CloseHandle(loop->iocp); loop->iocp = INVALID_HANDLE_VALUE; return err; }
int uv_interface_addresses(uv_interface_address_t** addresses_ptr, int* count_ptr) { IP_ADAPTER_ADDRESSES* win_address_buf; ULONG win_address_buf_size; IP_ADAPTER_ADDRESSES* adapter; uv_interface_address_t* uv_address_buf; char* name_buf; size_t uv_address_buf_size; uv_interface_address_t* uv_address; int count; int is_vista_or_greater; ULONG flags; is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0); if (is_vista_or_greater) { flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; } else { /* We need at least XP SP1. */ if (!is_windows_version_or_greater(5, 1, 1, 0)) return UV_ENOTSUP; flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX; } /* Fetch the size of the adapters reported by windows, and then get the */ /* list itself. */ win_address_buf_size = 0; win_address_buf = NULL; for (;;) { ULONG r; /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */ /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ /* win_address_buf_size. */ r = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, win_address_buf, &win_address_buf_size); if (r == ERROR_SUCCESS) break; uv__free(win_address_buf); switch (r) { case ERROR_BUFFER_OVERFLOW: /* This happens when win_address_buf is NULL or too small to hold */ /* all adapters. */ win_address_buf = uv__malloc(win_address_buf_size); if (win_address_buf == NULL) return UV_ENOMEM; continue; case ERROR_NO_DATA: { /* No adapters were found. */ uv_address_buf = uv__malloc(1); if (uv_address_buf == NULL) return UV_ENOMEM; *count_ptr = 0; *addresses_ptr = uv_address_buf; return 0; } case ERROR_ADDRESS_NOT_ASSOCIATED: return UV_EAGAIN; case ERROR_INVALID_PARAMETER: /* MSDN says: * "This error is returned for any of the following conditions: the * SizePointer parameter is NULL, the Address parameter is not * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for * the parameters requested is greater than ULONG_MAX." * Since the first two conditions are not met, it must be that the * adapter data is too big. */ return UV_ENOBUFS; default: /* Other (unspecified) errors can happen, but we don't have any */ /* special meaning for them. */ assert(r != ERROR_SUCCESS); return uv_translate_sys_error(r); } } /* Count the number of enabled interfaces and compute how much space is */ /* needed to store their info. */ count = 0; uv_address_buf_size = 0; for (adapter = win_address_buf; adapter != NULL; adapter = adapter->Next) { IP_ADAPTER_UNICAST_ADDRESS* unicast_address; int name_size; /* Interfaces that are not 'up' should not be reported. Also skip */ /* interfaces that have no associated unicast address, as to avoid */ /* allocating space for the name for this interface. */ if (adapter->OperStatus != IfOperStatusUp || adapter->FirstUnicastAddress == NULL) continue; /* Compute the size of the interface name. */ name_size = WideCharToMultiByte(CP_UTF8, 0, adapter->FriendlyName, -1, NULL, 0, NULL, FALSE); if (name_size <= 0) { uv__free(win_address_buf); return uv_translate_sys_error(GetLastError()); } uv_address_buf_size += name_size; /* Count the number of addresses associated with this interface, and */ /* compute the size. */ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) adapter->FirstUnicastAddress; unicast_address != NULL; unicast_address = unicast_address->Next) { count++; uv_address_buf_size += sizeof(uv_interface_address_t); } } /* Allocate space to store interface data plus adapter names. */ uv_address_buf = uv__malloc(uv_address_buf_size); if (uv_address_buf == NULL) { uv__free(win_address_buf); return UV_ENOMEM; } /* Compute the start of the uv_interface_address_t array, and the place in */ /* the buffer where the interface names will be stored. */ uv_address = uv_address_buf; name_buf = (char*) (uv_address_buf + count); /* Fill out the output buffer. */ for (adapter = win_address_buf; adapter != NULL; adapter = adapter->Next) { IP_ADAPTER_UNICAST_ADDRESS* unicast_address; int name_size; size_t max_name_size; if (adapter->OperStatus != IfOperStatusUp || adapter->FirstUnicastAddress == NULL) continue; /* Convert the interface name to UTF8. */ max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; if (max_name_size > (size_t) INT_MAX) max_name_size = INT_MAX; name_size = WideCharToMultiByte(CP_UTF8, 0, adapter->FriendlyName, -1, name_buf, (int) max_name_size, NULL, FALSE); if (name_size <= 0) { uv__free(win_address_buf); uv__free(uv_address_buf); return uv_translate_sys_error(GetLastError()); } /* Add an uv_interface_address_t element for every unicast address. */ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) adapter->FirstUnicastAddress; unicast_address != NULL; unicast_address = unicast_address->Next) { struct sockaddr* sa; ULONG prefix_len; sa = unicast_address->Address.lpSockaddr; /* XP has no OnLinkPrefixLength field. */ if (is_vista_or_greater) { prefix_len = ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength; } else { /* Prior to Windows Vista the FirstPrefix pointed to the list with * single prefix for each IP address assigned to the adapter. * Order of FirstPrefix does not match order of FirstUnicastAddress, * so we need to find corresponding prefix. */ IP_ADAPTER_PREFIX* prefix; prefix_len = 0; for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) { /* We want the longest matching prefix. */ if (prefix->Address.lpSockaddr->sa_family != sa->sa_family || prefix->PrefixLength <= prefix_len) continue; if (address_prefix_match(sa->sa_family, sa, prefix->Address.lpSockaddr, prefix->PrefixLength)) { prefix_len = prefix->PrefixLength; } } /* If there is no matching prefix information, return a single-host * subnet mask (e.g. 255.255.255.255 for IPv4). */ if (!prefix_len) prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32; } memset(uv_address, 0, sizeof *uv_address); uv_address->name = name_buf; if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) { memcpy(uv_address->phys_addr, adapter->PhysicalAddress, sizeof(uv_address->phys_addr)); } uv_address->is_internal = (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK); if (sa->sa_family == AF_INET6) { uv_address->address.address6 = *((struct sockaddr_in6 *) sa); uv_address->netmask.netmask6.sin6_family = AF_INET6; memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3); /* This check ensures that we don't write past the size of the data. */ if (prefix_len % 8) { uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] = 0xff << (8 - prefix_len % 8); } } else {
int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { uv_cpu_info_t* cpu_infos; SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; DWORD sppi_size; SYSTEM_INFO system_info; DWORD cpu_count, r, i; NTSTATUS status; ULONG result_size; int err; uv_cpu_info_t* cpu_info; cpu_infos = NULL; cpu_count = 0; sppi = NULL; uv__once_init(); GetSystemInfo(&system_info); cpu_count = system_info.dwNumberOfProcessors; cpu_infos = calloc(cpu_count, sizeof *cpu_infos); if (cpu_infos == NULL) { err = ERROR_OUTOFMEMORY; goto error; } sppi_size = cpu_count * sizeof(*sppi); sppi = uv__malloc(sppi_size); if (sppi == NULL) { err = ERROR_OUTOFMEMORY; goto error; } status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, sppi_size, &result_size); if (!NT_SUCCESS(status)) { err = pRtlNtStatusToDosError(status); goto error; } assert(result_size == sppi_size); for (i = 0; i < cpu_count; i++) { WCHAR key_name[128]; HKEY processor_key; DWORD cpu_speed; DWORD cpu_speed_size = sizeof(cpu_speed); WCHAR cpu_brand[256]; DWORD cpu_brand_size = sizeof(cpu_brand); size_t len; len = _snwprintf(key_name, ARRAY_SIZE(key_name), L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i); assert(len > 0 && len < ARRAY_SIZE(key_name)); r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_QUERY_VALUE, &processor_key); if (r != ERROR_SUCCESS) { err = GetLastError(); goto error; } if (RegQueryValueExW(processor_key, L"~MHz", NULL, NULL, (BYTE*) &cpu_speed, &cpu_speed_size) != ERROR_SUCCESS) { err = GetLastError(); RegCloseKey(processor_key); goto error; } if (RegQueryValueExW(processor_key, L"ProcessorNameString", NULL, NULL, (BYTE*) &cpu_brand, &cpu_brand_size) != ERROR_SUCCESS) { err = GetLastError(); RegCloseKey(processor_key); goto error; } RegCloseKey(processor_key); cpu_info = &cpu_infos[i]; cpu_info->speed = cpu_speed; cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - sppi[i].IdleTime.QuadPart) / 10000; cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000; cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; cpu_info->cpu_times.nice = 0; len = WideCharToMultiByte(CP_UTF8, 0, cpu_brand, cpu_brand_size / sizeof(WCHAR), NULL, 0, NULL, NULL); if (len == 0) { err = GetLastError(); goto error; } assert(len > 0); /* Allocate 1 extra byte for the null terminator. */ cpu_info->model = uv__malloc(len + 1); if (cpu_info->model == NULL) { err = ERROR_OUTOFMEMORY; goto error; } if (WideCharToMultiByte(CP_UTF8, 0, cpu_brand, cpu_brand_size / sizeof(WCHAR), cpu_info->model, len, NULL, NULL) == 0) { err = GetLastError(); goto error; } /* Ensure that cpu_info->model is null terminated. */ cpu_info->model[len] = '\0'; } uv__free(sppi); *cpu_count_ptr = cpu_count; *cpu_infos_ptr = cpu_infos; return 0; error: /* This is safe because the cpu_infos array is zeroed on allocation. */ for (i = 0; i < cpu_count; i++) uv__free(cpu_infos[i].model); uv__free(cpu_infos); uv__free(sppi); return uv_translate_sys_error(err); }
void uv_freeaddrinfo(struct addrinfo* ai) { char* alloc_ptr = (char*)ai; /* release copied result memory */ uv__free(alloc_ptr); }
static ssize_t uv__fs_write(uv_fs_t* req) { #if defined(__linux__) static int no_pwritev; #endif ssize_t r; /* Serialize writes on OS X, concurrent write() and pwrite() calls result in * data loss. We can't use a per-file descriptor lock, the descriptor may be * a dup(). */ #if defined(__APPLE__) static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&lock); #endif if (req->off < 0) { if (req->nbufs == 1) r = write(req->file, req->bufs[0].base, req->bufs[0].len); else r = writev(req->file, (struct iovec*) req->bufs, req->nbufs); } else { if (req->nbufs == 1) { r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); goto done; } #if HAVE_PREADV r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); #else # if defined(__linux__) if (no_pwritev) retry: # endif { off_t written; size_t index; written = 0; index = 0; r = 0; do { if (req->bufs[index].len > 0) { r = pwrite(req->file, req->bufs[index].base, req->bufs[index].len, req->off + written); if (r > 0) written += r; } index++; } while (index < req->nbufs && r >= 0); if (written > 0) r = written; } # if defined(__linux__) else { r = uv__pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); if (r == -1 && errno == ENOSYS) { no_pwritev = 1; goto retry; } } # endif #endif } done: #if defined(__APPLE__) pthread_mutex_unlock(&lock); #endif if (req->bufs != req->bufsml) uv__free(req->bufs); return r; }
/* * Entry point for getaddrinfo * we convert the UTF-8 strings to UNICODE * and save the UNICODE string pointers in the req * We also copy hints so that caller does not need to keep memory until the * callback. * return 0 if a callback will be made * return error code if validation fails * * To minimize allocation we calculate total size required, * and copy all structs and referenced strings into the one block. * Each size calculation is adjusted to avoid unaligned pointers. */ int uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, const struct addrinfo* hints) { int nodesize = 0; int servicesize = 0; int hintssize = 0; char* alloc_ptr = NULL; int err; if (req == NULL || (node == NULL && service == NULL)) { return UV_EINVAL; } UV_REQ_INIT(req, UV_GETADDRINFO); req->getaddrinfo_cb = getaddrinfo_cb; req->addrinfo = NULL; req->loop = loop; req->retcode = 0; /* calculate required memory size for all input values */ if (node != NULL) { nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * sizeof(WCHAR)); if (nodesize == 0) { err = GetLastError(); goto error; } } if (service != NULL) { servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, service, -1, NULL, 0) * sizeof(WCHAR)); if (servicesize == 0) { err = GetLastError(); goto error; } } if (hints != NULL) { hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW)); } /* allocate memory for inputs, and partition it as needed */ alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize); if (!alloc_ptr) { err = WSAENOBUFS; goto error; } /* save alloc_ptr now so we can free if error */ req->alloc = (void*)alloc_ptr; /* Convert node string to UTF16 into allocated memory and save pointer in the * request. */ if (node != NULL) { req->node = (WCHAR*)alloc_ptr; if (MultiByteToWideChar(CP_UTF8, 0, node, -1, (WCHAR*) alloc_ptr, nodesize / sizeof(WCHAR)) == 0) { err = GetLastError(); goto error; } alloc_ptr += nodesize; } else { req->node = NULL; } /* Convert service string to UTF16 into allocated memory and save pointer in * the req. */ if (service != NULL) { req->service = (WCHAR*)alloc_ptr; if (MultiByteToWideChar(CP_UTF8, 0, service, -1, (WCHAR*) alloc_ptr, servicesize / sizeof(WCHAR)) == 0) { err = GetLastError(); goto error; } alloc_ptr += servicesize; } else { req->service = NULL; } /* copy hints to allocated memory and save pointer in req */ if (hints != NULL) { req->addrinfow = (struct addrinfoW*)alloc_ptr; req->addrinfow->ai_family = hints->ai_family; req->addrinfow->ai_socktype = hints->ai_socktype; req->addrinfow->ai_protocol = hints->ai_protocol; req->addrinfow->ai_flags = hints->ai_flags; req->addrinfow->ai_addrlen = 0; req->addrinfow->ai_canonname = NULL; req->addrinfow->ai_addr = NULL; req->addrinfow->ai_next = NULL; } else { req->addrinfow = NULL; } uv__req_register(loop, req); if (getaddrinfo_cb) { uv__work_submit(loop, &req->work_req, UV__WORK_SLOW_IO, uv__getaddrinfo_work, uv__getaddrinfo_done); return 0; } else { uv__getaddrinfo_work(&req->work_req); uv__getaddrinfo_done(&req->work_req, 0); return req->retcode; } error: if (req != NULL) { uv__free(req->alloc); req->alloc = NULL; } return uv_translate_sys_error(err); }
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) { int name_size, is_path_dir; DWORD attr, last_error; WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; WCHAR short_path[MAX_PATH]; if (uv__is_active(handle)) return UV_EINVAL; handle->cb = cb; handle->path = uv__strdup(path); if (!handle->path) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } uv__handle_start(handle); /* Convert name to UTF16. */ name_size = uv_utf8_to_utf16(path, NULL, 0) * sizeof(WCHAR); pathw = (WCHAR*)uv__malloc(name_size); if (!pathw) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } if (!uv_utf8_to_utf16(path, pathw, name_size / sizeof(WCHAR))) { return uv_translate_sys_error(GetLastError()); } /* Determine whether path is a file or a directory. */ attr = GetFileAttributesW(pathw); if (attr == INVALID_FILE_ATTRIBUTES) { last_error = GetLastError(); goto error; } is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; if (is_path_dir) { /* path is a directory, so that's the directory that we will watch. */ handle->dirw = pathw; dir_to_watch = pathw; } else { /* * path is a file. So we split path into dir & file parts, and * watch the dir directory. */ /* Convert to short path. */ if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { last_error = GetLastError(); goto error; } if (uv_split_path(pathw, &dir, &handle->filew) != 0) { last_error = GetLastError(); goto error; } if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) { last_error = GetLastError(); goto error; } dir_to_watch = dir; uv__free(pathw); pathw = NULL; } handle->dir_handle = CreateFileW(dir_to_watch, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); if (dir) { uv__free(dir); dir = NULL; } if (handle->dir_handle == INVALID_HANDLE_VALUE) { last_error = GetLastError(); goto error; } if (CreateIoCompletionPort(handle->dir_handle, handle->loop->iocp, (ULONG_PTR)handle, 0) == NULL) { last_error = GetLastError(); goto error; } if (!handle->buffer) { handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size); } if (!handle->buffer) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } memset(&(handle->req.u.io.overlapped), 0, sizeof(handle->req.u.io.overlapped)); if (!ReadDirectoryChangesW(handle->dir_handle, handle->buffer, uv_directory_watcher_buffer_size, (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, NULL, &handle->req.u.io.overlapped, NULL)) { last_error = GetLastError(); goto error; } handle->req_pending = 1; return 0; error: if (handle->path) { uv__free(handle->path); handle->path = NULL; } if (handle->filew) { uv__free(handle->filew); handle->filew = NULL; } if (handle->short_filew) { uv__free(handle->short_filew); handle->short_filew = NULL; } uv__free(pathw); if (handle->dir_handle != INVALID_HANDLE_VALUE) { CloseHandle(handle->dir_handle); handle->dir_handle = INVALID_HANDLE_VALUE; } if (handle->buffer) { uv__free(handle->buffer); handle->buffer = NULL; } return uv_translate_sys_error(last_error); }
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus, cur = 0; uv_cpu_info_t* cpu_info; const char* maxcpus_key; const char* cptimes_key; char model[512]; long* cp_times; int numcpus; size_t size; int i; #if defined(__DragonFly__) /* This is not quite correct but DragonFlyBSD doesn't seem to have anything * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total, * not per CPU). At least this stops uv_cpu_info() from failing completely. */ maxcpus_key = "hw.ncpu"; cptimes_key = "kern.cp_time"; #else maxcpus_key = "kern.smp.maxcpus"; cptimes_key = "kern.cp_times"; #endif size = sizeof(model); if (sysctlbyname("hw.model", &model, &size, NULL, 0)) return -errno; size = sizeof(numcpus); if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) return -errno; *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) return -ENOMEM; *count = numcpus; size = sizeof(cpuspeed); if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { uv__free(*cpu_infos); return -errno; } /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of * ncpu. */ size = sizeof(maxcpus); if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { uv__free(*cpu_infos); return -errno; } size = maxcpus * CPUSTATES * sizeof(long); cp_times = uv__malloc(size); if (cp_times == NULL) { uv__free(*cpu_infos); return -ENOMEM; } if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { uv__free(cp_times); uv__free(*cpu_infos); return -errno; } for (i = 0; i < numcpus; i++) { cpu_info = &(*cpu_infos)[i]; cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; cpu_info->model = uv__strdup(model); cpu_info->speed = cpuspeed; cur+=CPUSTATES; } uv__free(cp_times); return 0; }
int uv__getpwuid_r(uv_passwd_t* pwd) { struct passwd pw; struct passwd* result; char* buf; uid_t uid; size_t bufsize; size_t name_size; size_t homedir_size; size_t shell_size; long initsize; int r; #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); if (getpwuid_r == NULL) return -ENOSYS; #endif if (pwd == NULL) return -EINVAL; initsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (initsize <= 0) bufsize = 4096; else bufsize = (size_t) initsize; uid = geteuid(); buf = NULL; for (;;) { uv__free(buf); buf = uv__malloc(bufsize); if (buf == NULL) return -ENOMEM; r = getpwuid_r(uid, &pw, buf, bufsize, &result); if (r != ERANGE) break; bufsize *= 2; } if (r != 0) { uv__free(buf); return -r; } if (result == NULL) { uv__free(buf); return -ENOENT; } /* Allocate memory for the username, shell, and home directory */ name_size = strlen(pw.pw_name) + 1; homedir_size = strlen(pw.pw_dir) + 1; shell_size = strlen(pw.pw_shell) + 1; pwd->username = uv__malloc(name_size + homedir_size + shell_size); if (pwd->username == NULL) { uv__free(buf); return -ENOMEM; } /* Copy the username */ memcpy(pwd->username, pw.pw_name, name_size); /* Copy the home directory */ pwd->homedir = pwd->username + name_size; memcpy(pwd->homedir, pw.pw_dir, homedir_size); /* Copy the shell */ pwd->shell = pwd->homedir + homedir_size; memcpy(pwd->shell, pw.pw_shell, shell_size); /* Copy the uid and gid */ pwd->uid = pw.pw_uid; pwd->gid = pw.pw_gid; uv__free(buf); return 0; }
/* * Helper function for search_path */ static WCHAR* search_path_join_test(const WCHAR* dir, size_t dir_len, const WCHAR* name, size_t name_len, const WCHAR* ext, size_t ext_len, const WCHAR* cwd, size_t cwd_len) { WCHAR *result, *result_pos; DWORD attrs; if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') { /* It's a UNC path so ignore cwd */ cwd_len = 0; } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) { /* It's a full path without drive letter, use cwd's drive letter only */ cwd_len = 2; } else if (dir_len >= 2 && dir[1] == L':' && (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) { /* It's a relative path with drive letter (ext.g. D:../some/file) * Replace drive letter in dir by full cwd if it points to the same drive, * otherwise use the dir only. */ if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) { cwd_len = 0; } else { dir += 2; dir_len -= 2; } } else if (dir_len > 2 && dir[1] == L':') { /* It's an absolute path with drive letter * Don't use the cwd at all */ cwd_len = 0; } /* Allocate buffer for output */ result = result_pos = (WCHAR*)uv__malloc(sizeof(WCHAR) * (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1)); /* Copy cwd */ wcsncpy(result_pos, cwd, cwd_len); result_pos += cwd_len; /* Add a path separator if cwd didn't end with one */ if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) { result_pos[0] = L'\\'; result_pos++; } /* Copy dir */ wcsncpy(result_pos, dir, dir_len); result_pos += dir_len; /* Add a separator if the dir didn't end with one */ if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) { result_pos[0] = L'\\'; result_pos++; } /* Copy filename */ wcsncpy(result_pos, name, name_len); result_pos += name_len; if (ext_len) { /* Add a dot if the filename didn't end with one */ if (name_len && result_pos[-1] != '.') { result_pos[0] = L'.'; result_pos++; } /* Copy extension */ wcsncpy(result_pos, ext, ext_len); result_pos += ext_len; } /* Null terminator */ result_pos[0] = L'\0'; attrs = GetFileAttributesW(result); if (attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY)) { return result; } uv__free(result); return NULL; }
int uv_os_homedir(char* buffer, size_t* size) { struct passwd pw; struct passwd* result; char* buf; uid_t uid; size_t bufsize; size_t len; long initsize; int r; if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; /* Check if the HOME environment variable is set first */ buf = getenv("HOME"); if (buf != NULL) { len = strlen(buf); if (len >= *size) { *size = len; return -ENOBUFS; } memcpy(buffer, buf, len + 1); *size = len; return 0; } /* HOME is not set, so call getpwuid() */ initsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (initsize <= 0) bufsize = 4096; else bufsize = (size_t) initsize; uid = getuid(); buf = NULL; for (;;) { uv__free(buf); buf = uv__malloc(bufsize); if (buf == NULL) return -ENOMEM; r = getpwuid_r(uid, &pw, buf, bufsize, &result); if (r != ERANGE) break; bufsize *= 2; } if (r != 0) { uv__free(buf); return -r; } if (result == NULL) { uv__free(buf); return -ENOENT; } len = strlen(pw.pw_dir); if (len >= *size) { *size = len; uv__free(buf); return -ENOBUFS; } memcpy(buffer, pw.pw_dir, len + 1); *size = len; uv__free(buf); return 0; }
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle) { FILE_NOTIFY_INFORMATION* file_info; int err, sizew, size, result; char* filename = NULL; WCHAR* filenamew, *long_filenamew = NULL; DWORD offset = 0; assert(req->type == UV_FS_EVENT_REQ); assert(handle->req_pending); handle->req_pending = 0; /* Don't report any callbacks if: * - We're closing, just push the handle onto the endgame queue * - We are not active, just ignore the callback */ if (!uv__is_active(handle)) { if (handle->flags & UV__HANDLE_CLOSING) { uv_want_endgame(loop, (uv_handle_t*) handle); } return; } file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset); if (REQ_SUCCESS(req)) { if (req->u.io.overlapped.InternalHigh > 0) { do { file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset); assert(!filename); assert(!long_filenamew); /* * Fire the event only if we were asked to watch a directory, * or if the filename filter matches. */ if (handle->dirw || _wcsnicmp(handle->filew, file_info->FileName, file_info->FileNameLength / sizeof(WCHAR)) == 0 || _wcsnicmp(handle->short_filew, file_info->FileName, file_info->FileNameLength / sizeof(WCHAR)) == 0) { if (handle->dirw) { /* * We attempt to resolve the long form of the file name explicitly. * We only do this for file names that might still exist on disk. * If this fails, we use the name given by ReadDirectoryChangesW. * This may be the long form or the 8.3 short name in some cases. */ if (file_info->Action != FILE_ACTION_REMOVED && file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) { /* Construct a full path to the file. */ size = wcslen(handle->dirw) + file_info->FileNameLength / sizeof(WCHAR) + 2; filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR)); if (!filenamew) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw, file_info->FileNameLength / sizeof(WCHAR), file_info->FileName); filenamew[size - 1] = L'\0'; /* Convert to long name. */ size = GetLongPathNameW(filenamew, NULL, 0); if (size) { long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR)); if (!long_filenamew) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } size = GetLongPathNameW(filenamew, long_filenamew, size); if (size) { long_filenamew[size] = '\0'; } else { uv__free(long_filenamew); long_filenamew = NULL; } } uv__free(filenamew); if (long_filenamew) { /* Get the file name out of the long path. */ result = uv_relative_path(long_filenamew, handle->dirw, &filenamew); uv__free(long_filenamew); if (result == 0) { long_filenamew = filenamew; sizew = -1; } else { long_filenamew = NULL; } } /* * We could not resolve the long form explicitly. * We therefore use the name given by ReadDirectoryChangesW. * This may be the long form or the 8.3 short name in some cases. */ if (!long_filenamew) { filenamew = file_info->FileName; sizew = file_info->FileNameLength / sizeof(WCHAR); } } else { /* * Removed or renamed events cannot be resolved to the long form. * We therefore use the name given by ReadDirectoryChangesW. * This may be the long form or the 8.3 short name in some cases. */ if (!long_filenamew) { filenamew = file_info->FileName; sizew = file_info->FileNameLength / sizeof(WCHAR); } } } else { /* We already have the long name of the file, so just use it. */ filenamew = handle->filew; sizew = -1; } if (filenamew) { /* Convert the filename to utf8. */ size = uv_utf16_to_utf8(filenamew, sizew, NULL, 0); if (size) { filename = (char*)uv__malloc(size + 1); if (!filename) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } size = uv_utf16_to_utf8(filenamew, sizew, filename, size); if (size) { filename[size] = '\0'; } else { uv__free(filename); filename = NULL; } } } switch (file_info->Action) { case FILE_ACTION_ADDED: case FILE_ACTION_REMOVED: case FILE_ACTION_RENAMED_OLD_NAME: case FILE_ACTION_RENAMED_NEW_NAME: handle->cb(handle, filename, UV_RENAME, 0); break; case FILE_ACTION_MODIFIED: handle->cb(handle, filename, UV_CHANGE, 0); break; } uv__free(filename); filename = NULL; uv__free(long_filenamew); long_filenamew = NULL; } offset = file_info->NextEntryOffset; } while (offset && !(handle->flags & UV__HANDLE_CLOSING)); } else { handle->cb(handle, NULL, UV_CHANGE, 0); } } else { err = GET_REQ_ERROR(req); handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); } if (!(handle->flags & UV__HANDLE_CLOSING)) { uv_fs_event_queue_readdirchanges(loop, handle); } else { uv_want_endgame(loop, (uv_handle_t*)handle); } }
int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { char** arg; WCHAR* dst = NULL; WCHAR* temp_buffer = NULL; size_t dst_len = 0; size_t temp_buffer_len = 0; WCHAR* pos; int arg_count = 0; int err = 0; /* Count the required size. */ for (arg = args; *arg; arg++) { DWORD arg_len; arg_len = MultiByteToWideChar(CP_UTF8, 0, *arg, -1, NULL, 0); if (arg_len == 0) { return GetLastError(); } dst_len += arg_len; if (arg_len > temp_buffer_len) temp_buffer_len = arg_len; arg_count++; } /* Adjust for potential quotes. Also assume the worst-case scenario */ /* that every character needs escaping, so we need twice as much space. */ dst_len = dst_len * 2 + arg_count * 2; /* Allocate buffer for the final command line. */ dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR)); if (dst == NULL) { err = ERROR_OUTOFMEMORY; goto error; } /* Allocate temporary working buffer. */ temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR)); if (temp_buffer == NULL) { err = ERROR_OUTOFMEMORY; goto error; } pos = dst; for (arg = args; *arg; arg++) { DWORD arg_len; /* Convert argument to wide char. */ arg_len = MultiByteToWideChar(CP_UTF8, 0, *arg, -1, temp_buffer, (int) (dst + dst_len - pos)); if (arg_len == 0) { err = GetLastError(); goto error; } if (verbatim_arguments) { /* Copy verbatim. */ wcscpy(pos, temp_buffer); pos += arg_len - 1; } else { /* Quote/escape, if needed. */ pos = quote_cmd_arg(temp_buffer, pos); } *pos++ = *(arg + 1) ? L' ' : L'\0'; } uv__free(temp_buffer); *dst_ptr = dst; return 0; error: uv__free(dst); uv__free(temp_buffer); return err; }
int broker_start_server(json_t *config) { json_incref(config); const char *httpHost = NULL; char httpPort[8]; memset(httpPort, 0, sizeof(httpPort)); { json_t *http = json_object_get(config, "http"); if (http) { json_t *enabled = json_object_get(http, "enabled"); if (!(enabled && json_boolean_value(enabled))) { json_decref(config); return 0; } httpHost = json_string_value(json_object_get(http, "host")); json_t *jsonPort = json_object_get(http, "port"); if (jsonPort) { json_int_t p = json_integer_value(jsonPort); int len = snprintf(httpPort, sizeof(httpPort) - 1, "%" JSON_INTEGER_FORMAT, p); httpPort[len] = '\0'; } } } int httpActive = 0; Server httpServer; uv_poll_t httpPoll; if (httpHost && httpPort[0] != '\0') { mbedtls_net_init(&httpServer.srv); httpServer.data_ready = broker_on_data_callback; httpActive = start_http_server(&httpServer, httpHost, httpPort, mainLoop, &httpPoll); } uv_signal_t sigInt; uv_signal_init(mainLoop, &sigInt); uv_signal_start(&sigInt, stop_server_handler, SIGINT); uv_signal_t sigTerm; uv_signal_init(mainLoop, &sigTerm); uv_signal_start(&sigTerm, stop_server_handler, SIGTERM); // upstream_connect_conn(&loop, "http://10.0.1.158:8080/conn", "dartbroker", "cbroker"); if (httpActive) { uv_run(mainLoop, UV_RUN_DEFAULT); } uv_signal_stop(&sigInt); uv_signal_stop(&sigTerm); if (httpActive) { uv_poll_stop(&httpPoll); } uv_loop_close(mainLoop); #if defined(__unix__) || defined(__APPLE__) if (mainLoop && mainLoop->watchers) { uv__free(mainLoop->watchers); } #endif json_decref(config); return 0; }
/* * The way windows takes environment variables is different than what C does; * Windows wants a contiguous block of null-terminated strings, terminated * with an additional null. * * Windows has a few "essential" environment variables. winsock will fail * to initialize if SYSTEMROOT is not defined; some APIs make reference to * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that * these get defined if the input environment block does not contain any * values for them. * * Also add variables known to Cygwin to be required for correct * subprocess operation in many cases: * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955 * */ int make_program_env(char* env_block[], WCHAR** dst_ptr) { WCHAR* dst; WCHAR* ptr; char** env; size_t env_len = 0; int len; size_t i; DWORD var_size; size_t env_block_count = 1; /* 1 for null-terminator */ WCHAR* dst_copy; WCHAR** ptr_copy; WCHAR** env_copy; DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*)); /* first pass: determine size in UTF-16 */ for (env = env_block; *env; env++) { int len; if (strchr(*env, '=')) { len = MultiByteToWideChar(CP_UTF8, 0, *env, -1, NULL, 0); if (len <= 0) { return GetLastError(); } env_len += len; env_block_count++; } } /* second pass: copy to UTF-16 environment block */ dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR)); if (!dst_copy) { return ERROR_OUTOFMEMORY; } env_copy = alloca(env_block_count * sizeof(WCHAR*)); ptr = dst_copy; ptr_copy = env_copy; for (env = env_block; *env; env++) { if (strchr(*env, '=')) { len = MultiByteToWideChar(CP_UTF8, 0, *env, -1, ptr, (int) (env_len - (ptr - dst_copy))); if (len <= 0) { DWORD err = GetLastError(); uv__free(dst_copy); return err; } *ptr_copy++ = ptr; ptr += len; } } *ptr_copy = NULL; assert(env_len == ptr - dst_copy); /* sort our (UTF-16) copy */ qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp); /* third pass: check for required variables */ for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) { int cmp; if (!*ptr_copy) { cmp = -1; } else { cmp = env_strncmp(required_vars[i].wide_eq, required_vars[i].len, *ptr_copy); } if (cmp < 0) { /* missing required var */ var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0); required_vars_value_len[i] = var_size; if (var_size != 0) { env_len += required_vars[i].len; env_len += var_size; } i++; } else { ptr_copy++; if (cmp == 0) i++; } } /* final pass: copy, in sort order, and inserting required variables */ dst = uv__malloc((1+env_len) * sizeof(WCHAR)); if (!dst) { uv__free(dst_copy); return ERROR_OUTOFMEMORY; } for (ptr = dst, ptr_copy = env_copy, i = 0; *ptr_copy || i < n_required_vars; ptr += len) { int cmp; if (i >= n_required_vars) { cmp = 1; } else if (!*ptr_copy) { cmp = -1; } else { cmp = env_strncmp(required_vars[i].wide_eq, required_vars[i].len, *ptr_copy); } if (cmp < 0) { /* missing required var */ len = required_vars_value_len[i]; if (len) { wcscpy(ptr, required_vars[i].wide_eq); ptr += required_vars[i].len; var_size = GetEnvironmentVariableW(required_vars[i].wide, ptr, (int) (env_len - (ptr - dst))); if (var_size != len-1) { /* race condition? */ uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); } } i++; } else { /* copy var from env_block */ len = wcslen(*ptr_copy) + 1; wmemcpy(ptr, *ptr_copy, len); ptr_copy++; if (cmp == 0) i++; } } /* Terminate with an extra NULL. */ assert(env_len == (ptr - dst)); *ptr = L'\0'; uv__free(dst_copy); *dst_ptr = dst; return 0; }