static void accept_loop(FileDescriptor&& listenerDescriptor) { auto listener = w_stm_fdopen(std::move(listenerDescriptor)); while (!stopping) { FileDescriptor client_fd; struct watchman_event_poll pfd[2]; int bufsize; #ifdef HAVE_LIBGIMLI_H if (hb) { gimli_heartbeat_set(hb, GIMLI_HB_RUNNING); } #endif pfd[0].evt = listener->getEvents(); pfd[1].evt = listener_thread_event.get(); if (w_poll_events(pfd, 2, 60000) == 0) { if (stopping) { break; } // Timed out, or error. // Arrange to sanity check that we're working w_check_my_sock(); continue; } if (stopping) { break; } #ifdef HAVE_ACCEPT4 client_fd = FileDescriptor( accept4(listener->getFileDescriptor().fd(), nullptr, 0, SOCK_CLOEXEC)); #else client_fd = FileDescriptor(accept(listener->getFileDescriptor().fd(), nullptr, 0)); #endif if (!client_fd) { continue; } client_fd.setCloExec(); bufsize = WATCHMAN_IO_BUF_SIZE; setsockopt( client_fd.fd(), SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(bufsize)); make_new_client(w_stm_fdopen(std::move(client_fd))); } }
// If we are running under inetd-style supervision, call this function // to move the inetd provided socket descriptor(s) to a new descriptor // number and remember that we can just use these when we're starting // up the listener. void w_listener_prep_inetd() { if (listener_fd) { throw std::runtime_error( "w_listener_prep_inetd: listener_fd is already assigned"); } listener_fd = FileDescriptor(dup(STDIN_FILENO), "dup(stdin) for listener"); }
static FileDescriptor create_pipe_server(const char* path) { return FileDescriptor(intptr_t(CreateNamedPipe( path, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS, PIPE_UNLIMITED_INSTANCES, WATCHMAN_IO_BUF_SIZE, 512, 0, nullptr))); }
static FileDescriptor get_listener_socket(const char *path) { struct sockaddr_un un; mode_t perms = cfg_get_perms( "sock_access", true /* write bits */, false /* execute bits */); FileDescriptor listener_fd; #ifdef __APPLE__ listener_fd = w_get_listener_socket_from_launchd(); if (listener_fd) { w_log(W_LOG_ERR, "Using socket from launchd as listening socket\n"); return listener_fd; } #endif if (strlen(path) >= sizeof(un.sun_path) - 1) { w_log(W_LOG_ERR, "%s: path is too long\n", path); return FileDescriptor(); } listener_fd = FileDescriptor(socket(PF_LOCAL, SOCK_STREAM, 0), "socket"); un.sun_family = PF_LOCAL; memcpy(un.sun_path, path, strlen(path) + 1); unlink(path); if (bind(listener_fd.fd(), (struct sockaddr*)&un, sizeof(un)) != 0) { w_log(W_LOG_ERR, "bind(%s): %s\n", path, strerror(errno)); return FileDescriptor(); } // The permissions in the containing directory should be correct, so this // should be correct as well. But set the permissions in any case. if (chmod(path, perms) == -1) { w_log(W_LOG_ERR, "chmod(%s, %#o): %s", path, perms, strerror(errno)); return FileDescriptor(); } // Double-check that the socket has the right permissions. This can happen // when the containing directory was created in a previous run, with a group // the user is no longer in. struct stat st; if (lstat(path, &st) == -1) { watchman::log(watchman::ERR, "lstat(", path, "): ", strerror(errno), "\n"); return FileDescriptor(); } // This is for testing only // (test_sock_perms.py:test_user_previously_in_sock_group). Do not document. const char *sock_group_name = cfg_get_string("__sock_file_group", nullptr); if (!sock_group_name) { sock_group_name = cfg_get_string("sock_group", nullptr); } if (sock_group_name) { const struct group *sock_group = w_get_group(sock_group_name); if (!sock_group) { return FileDescriptor(); } if (st.st_gid != sock_group->gr_gid) { watchman::log( watchman::ERR, "for socket '", path, "', gid ", st.st_gid, " doesn't match expected gid ", sock_group->gr_gid, " (group name ", sock_group_name, "). Ensure that you are still a member of group ", sock_group_name, ".\n"); return FileDescriptor(); } } if (listen(listener_fd.fd(), 200) != 0) { w_log(W_LOG_ERR, "listen(%s): %s\n", path, strerror(errno)); return FileDescriptor(); } return listener_fd; }
static void named_pipe_accept_loop_internal(const char* path) { HANDLE handles[2]; auto olap = OVERLAPPED(); HANDLE connected_event = CreateEvent(NULL, FALSE, TRUE, NULL); if (!connected_event) { w_log( W_LOG_ERR, "named_pipe_accept_loop_internal: CreateEvent failed: %s\n", win32_strerror(GetLastError())); return; } handles[0] = connected_event; handles[1] = listener_thread_event; olap.hEvent = connected_event; w_log(W_LOG_ERR, "waiting for pipe clients on %s\n", path); while (!stopping) { FileDescriptor client_fd; DWORD res; client_fd = FileDescriptor(intptr_t(CreateNamedPipe( path, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS, PIPE_UNLIMITED_INSTANCES, WATCHMAN_IO_BUF_SIZE, 512, 0, nullptr))); if (!client_fd) { w_log(W_LOG_ERR, "CreateNamedPipe(%s) failed: %s\n", path, win32_strerror(GetLastError())); continue; } ResetEvent(connected_event); if (!ConnectNamedPipe((HANDLE)client_fd.handle(), &olap)) { res = GetLastError(); if (res == ERROR_PIPE_CONNECTED) { make_new_client(w_stm_fdopen(std::move(client_fd))); continue; } if (res != ERROR_IO_PENDING) { w_log(W_LOG_ERR, "ConnectNamedPipe: %s\n", win32_strerror(GetLastError())); continue; } res = WaitForMultipleObjectsEx(2, handles, false, INFINITE, true); if (res == WAIT_OBJECT_0 + 1) { // Signalled to stop CancelIoEx((HANDLE)client_fd.handle(), &olap); continue; } if (res != WAIT_OBJECT_0) { w_log( W_LOG_ERR, "WaitForMultipleObjectsEx: ConnectNamedPipe: " "unexpected status %u\n", res); CancelIoEx((HANDLE)client_fd.handle(), &olap); continue; } } make_new_client(w_stm_fdopen(std::move(client_fd))); } }
KQueueWatcher::KQueueWatcher(w_root_t* root) : Watcher("kqueue", 0), maps_(maps(root->config.getInt(CFG_HINT_NUM_DIRS, HINT_NUM_DIRS))) { kq_fd = FileDescriptor(kqueue(), "kqueue"); kq_fd.setCloExec(); }