36 # include <sys/types.h>
38 # include <sys/wait.h>
56 # include <valgrind/memcheck.h>
64 #define LOCALHOST "127.0.0.1"
67 #define DEFAULT_PORT 1239
71 typedef pid_t pid_type;
72 #elif defined __WIN32__
73 typedef DWORD pid_type;
75 # error Neither HAVE_FORK nor __WIN32__ is defined
79 static constexpr pid_type DEAD_PID = 0;
102 db_internal =
nullptr;
105 void init(pid_type pid_, HANDLE handle_) {
108 db_internal =
nullptr;
115 if (pid == DEAD_PID)
return;
118 while (waitpid(pid, &status, 0) == -1 && errno == EINTR) { }
123 #elif defined __WIN32__
124 WaitForSingleObject(handle, INFINITE);
130 if (pid == DEAD_PID || dbi != db_internal)
return false;
134 if (kill(-pid, SIGKILL) < 0) {
138 #elif defined __WIN32__
142 if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid)) {
144 -
int(GetLastError()));
169 static std::pair<int, ServerData&>
170 launch_xapian_tcpsrv(
const string & args)
180 if (RUNNING_ON_VALGRIND) cmd =
"./runsrv " + cmd;
183 if (socketpair(AF_UNIX, SOCK_STREAM|
SOCK_CLOEXEC, PF_UNSPEC, fds) < 0) {
184 string msg(
"Couldn't create socketpair: ");
189 pid_t child = fork();
204 if (fds[1] == 1 || fds[1] == 2) {
211 execl(
"/bin/sh",
"/bin/sh",
"-c", cmd.c_str(),
static_cast<void*
>(0));
218 int fork_errno = errno;
220 string msg(
"Couldn't fork: ");
228 FILE * fh = fdopen(fds[0],
"r");
230 string msg(
"Failed to run command '");
240 if (fgets(buf,
sizeof(buf), fh) == NULL) {
244 if (waitpid(child, &status, 0) == -1) {
245 string msg(
"waitpid failed: ");
249 if (++port < 65536 && status != 0) {
250 if (WIFEXITED(status) &&
257 string msg(
"Failed to get 'Listening...' from command '");
259 msg +=
"' (output: ";
264 if (strcmp(buf,
"Listening...\n") == 0)
break;
280 #elif defined __WIN32__
283 static void win32_throw_error_string(
const char *
str)
288 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
289 0, GetLastError(), 0, (CHAR*)&error, 0, 0);
292 if (len >= 2 && error[len - 2] ==
'\r' && error[len - 1] ==
'\n')
296 msg.append(error, len);
305 static std::pair<int, ServerData&>
306 launch_xapian_tcpsrv(
const string & args)
317 HANDLE hRead, hWrite;
318 if (!CreatePipe(&hRead, &hWrite, 0, 0))
319 win32_throw_error_string(
"Couldn't create pipe");
322 SetHandleInformation(hWrite, HANDLE_FLAG_INHERIT, 1);
325 PROCESS_INFORMATION procinfo;
326 memset(&procinfo, 0,
sizeof(PROCESS_INFORMATION));
328 STARTUPINFO startupinfo;
329 memset(&startupinfo, 0,
sizeof(STARTUPINFO));
330 startupinfo.cb =
sizeof(STARTUPINFO);
331 startupinfo.hStdError = hWrite;
332 startupinfo.hStdOutput = hWrite;
333 startupinfo.hStdInput = INVALID_HANDLE_VALUE;
334 startupinfo.dwFlags |= STARTF_USESTDHANDLES;
339 CREATE_NEW_PROCESS_GROUP, 0, 0,
340 &startupinfo, &procinfo)) {
341 win32_throw_error_string(
"Couldn't create child process");
345 CloseHandle(procinfo.hThread);
348 FILE *fh = fdopen(_open_osfhandle(intptr_t(hRead), O_RDONLY),
"r");
351 if (fgets(buf,
sizeof(buf), fh) == NULL) {
356 while (GetExitCodeProcess(procinfo.hProcess, &rc) && rc == STILL_ACTIVE) {
359 CloseHandle(procinfo.hProcess);
365 string msg(
"Failed to get 'Listening...' from command '");
367 msg +=
"' (output: ";
372 if (strcmp(buf,
"Listening...\r\n") == 0)
break;
384 data.
init(procinfo.dwProcessId, procinfo.hProcess);
389 # error Neither HAVE_FORK nor __WIN32__ is defined
395 auto [port, server] = launch_xapian_tcpsrv(args);
396 if (port_ptr) *port_ptr = port;
398 server.set_db_internal(db.internal.get());
405 auto [port, server] = launch_xapian_tcpsrv(args);
407 server.set_db_internal(db.internal.get());
433 unsigned int timeout,
436 return get_remotetcp_db(get_remote_database_args(files, timeout), port_ptr);
void kill_remote(const Xapian::Database &db)
Kill the server associated with remote database db.
static Xapian::Database get_remotetcp_db(const string &args, int *port_ptr=nullptr)
static Xapian::WritableDatabase get_remotetcp_writable_db(const string &args)
static unsigned first_unused_server_data
static ServerData server_data[16]
BackendManager subclass for remotetcp databases.
Xapian::Database get_writable_database_as_database()
Create a Database object for the last opened WritableDatabase.
void clean_up()
Called after each test, to perform any necessary cleanup.
Xapian::WritableDatabase get_writable_database(const std::string &name, const std::string &file)
Create a RemoteTcp Xapian::WritableDatabase object indexing a single file.
Xapian::WritableDatabase get_writable_database_again()
Create a WritableDatabase object for the last opened WritableDatabase.
void kill_remote(const Xapian::Database &db)
Kill the remote server associated with db.
Xapian::Database get_remote_database(const std::vector< std::string > &files, unsigned int timeout, int *port_ptr)
Create a RemoteTcp Xapian::Database with the specified timeout.
~BackendManagerRemoteTcp()
Xapian::Database do_get_database(const std::vector< std::string > &files)
Create a Xapian::Database object indexing multiple files.
Xapian::Database get_database_by_path(const std::string &path)
Get a RemoteTcp Xapian::Database instance of the database at path.
void set_db_internal(const void *dbi)
bool kill_remote(const void *dbi)
const void * db_internal
The internal pointer of the Database object.
pid_type pid
The remote server process ID.
DatabaseError indicates some sort of database related error.
An indexed database of documents.
Xapian::Internal::intrusive_ptr_nonnull< Internal > internal
This class provides read/write access to a database.
void errno_to_string(int e, string &s)
Convert errno value to std::string, thread-safe if possible.
string str(int value)
Convert int to std::string.
WritableDatabase open_writable(std::string_view host, unsigned int port, unsigned timeout=0, unsigned connect_timeout=10000, int flags=0)
Construct a WritableDatabase object for update access to a remote database accessed via a TCP connect...
Database open(std::string_view host, unsigned int port, unsigned timeout=10000, unsigned connect_timeout=10000)
Construct a Database object for read-only access to a remote database accessed via a TCP connection.
include <fcntl.h>, but working around broken platforms.
include <sysexits.h> with portability workarounds.
include <sys/socket.h> with portability workarounds.
include <windows.h> without all the bloat and damage.
Convert types to std::string.
Public interfaces for the Xapian library.