36 # include <sys/types.h>    38 # include <sys/wait.h>    41 # if !defined SIGCHLD && defined SIGCLD    42 #  define SIGCHLD SIGCLD    61 # include <valgrind/memcheck.h>    69 #define LOCALHOST "127.0.0.1"    72 #define DEFAULT_PORT 1239    84 static pid_fd pid_to_fd[16];
    93     while ((child = waitpid(-1, &status, WNOHANG)) > 0) {
    94         for (
unsigned i = 0; i < 
sizeof(pid_to_fd) / 
sizeof(pid_fd); ++i) {
    95             if (pid_to_fd[i].pid == child) {
    96                 int fd = pid_to_fd[i].fd;
   110 launch_xapian_tcpsrv(
const string & args)
   116     signal(SIGCHLD, SIG_DFL);
   123     if (RUNNING_ON_VALGRIND) cmd = 
"./runsrv " + cmd;
   126     if (socketpair(AF_UNIX, SOCK_STREAM|
SOCK_CLOEXEC, PF_UNSPEC, fds) < 0) {
   127         string msg(
"Couldn't create socketpair: ");
   132     pid_t child = fork();
   147         if (fds[1] == 1 || fds[1] == 2) {
   154         execl(
"/bin/sh", 
"/bin/sh", 
"-c", cmd.c_str(), 
static_cast<void*
>(0));
   161         int fork_errno = errno;
   163         string msg(
"Couldn't fork: ");
   171     FILE * fh = fdopen(fds[0], 
"r");
   173         string msg(
"Failed to run command '");
   183         if (fgets(buf, 
sizeof(buf), fh) == NULL) {
   187             if (waitpid(child, &status, 0) == -1) {
   188                 string msg(
"waitpid failed: ");
   192             if (++port < 65536 && status != 0) {
   193                 if (WIFEXITED(status) &&
   200             string msg(
"Failed to get 'Listening...' from command '");
   202             msg += 
"' (output: ";
   207         if (strcmp(buf, 
"Listening...\n") == 0) 
break;
   213     int tracked_fd = dup(fds[0]);
   221     for (
unsigned i = 0; i < 
sizeof(pid_to_fd) / 
sizeof(pid_fd); ++i) {
   222         if (pid_to_fd[i].pid == 0) {
   223             pid_to_fd[i].fd = tracked_fd;
   224             pid_to_fd[i].pid = child;
   231     signal(SIGCHLD, on_SIGCHLD);
   236 #elif defined __WIN32__   238 static HANDLE tcpsrv_handles[16];
   239 static unsigned tcpsrv_handles_index = 0;
   241 static constexpr 
auto TCPSRV_HANDLES_INDEX_MAX =
   242         sizeof(tcpsrv_handles) / 
sizeof(tcpsrv_handles[0]);
   244 XAPIAN_NORETURN(
static void win32_throw_error_string(
const char * 
str));
   245 static void win32_throw_error_string(
const char * 
str)
   250     len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
   251                         0, GetLastError(), 0, (CHAR*)&error, 0, 0);
   254         if (len >= 2 && error[len - 2] == 
'\r' && error[len - 1] == 
'\n')
   258             msg.append(error, len);
   268 launch_xapian_tcpsrv(
const string & args)
   279     HANDLE hRead, hWrite;
   280     if (!CreatePipe(&hRead, &hWrite, 0, 0))
   281         win32_throw_error_string(
"Couldn't create pipe");
   284     SetHandleInformation(hWrite, HANDLE_FLAG_INHERIT, 1);
   287     PROCESS_INFORMATION procinfo;
   288     memset(&procinfo, 0, 
sizeof(PROCESS_INFORMATION));
   290     STARTUPINFO startupinfo;
   291     memset(&startupinfo, 0, 
sizeof(STARTUPINFO));
   292     startupinfo.cb = 
sizeof(STARTUPINFO);
   293     startupinfo.hStdError = hWrite;
   294     startupinfo.hStdOutput = hWrite;
   295     startupinfo.hStdInput = INVALID_HANDLE_VALUE;
   296     startupinfo.dwFlags |= STARTF_USESTDHANDLES;
   300     if (!CreateProcess(
XAPIAN_TCPSRV, &cmd[0], 0, 0, TRUE, 0, 0, 0,
   301                        &startupinfo, &procinfo)) {
   302         win32_throw_error_string(
"Couldn't create child process");
   306     CloseHandle(procinfo.hThread);
   309     FILE *fh = fdopen(_open_osfhandle(intptr_t(hRead), O_RDONLY), 
"r");
   312         if (fgets(buf, 
sizeof(buf), fh) == NULL) {
   317             while (GetExitCodeProcess(procinfo.hProcess, &rc) && rc == STILL_ACTIVE) {
   320             CloseHandle(procinfo.hProcess);
   326             string msg(
"Failed to get 'Listening...' from command '");
   328             msg += 
"' (output: ";
   333         if (strcmp(buf, 
"Listening...\r\n") == 0) 
break;
   338     if (tcpsrv_handles_index < TCPSRV_HANDLES_INDEX_MAX) {
   339         tcpsrv_handles[tcpsrv_handles_index++] = procinfo.hProcess;
   346 # error Neither HAVE_FORK nor __WIN32__ is defined   365     string args = get_writable_database_args(name, file);
   366     int port = launch_xapian_tcpsrv(args);
   374     string args = get_remote_database_args(files, timeout);
   375     int port = launch_xapian_tcpsrv(args);
   382     string args = get_remote_database_args(path, 300000);
   383     int port = launch_xapian_tcpsrv(args);
   390     string args = get_writable_database_as_database_args();
   391     int port = launch_xapian_tcpsrv(args);
   398     string args = get_writable_database_again_args();
   399     int port = launch_xapian_tcpsrv(args);
   407     signal(SIGCHLD, SIG_DFL);
   408     for (
unsigned i = 0; i < 
sizeof(pid_to_fd) / 
sizeof(pid_fd); ++i) {
   409         pid_t child = pid_to_fd[i].pid;
   412             while (waitpid(child, &status, 0) == -1 && errno == EINTR) { }
   417             int fd = pid_to_fd[i].fd;
   419             pid_to_fd[i].pid = 0;
   423 #elif defined __WIN32__   424     for (
unsigned i = 0; i != tcpsrv_handles_index; ++i) {
   425         WaitForSingleObject(tcpsrv_handles[i], INFINITE);
   426         CloseHandle(tcpsrv_handles[i]);
   428     tcpsrv_handles_index = 0;
 
Xapian::WritableDatabase get_writable_database(const std::string &name, const std::string &file)
Create a RemoteTcp Xapian::WritableDatabase object indexing a single file. 
 
~BackendManagerRemoteTcp()
 
Define the XAPIAN_NORETURN macro. 
 
This class is used to access a database, or a group of databases. 
 
Xapian::Database do_get_database(const std::vector< std::string > &files)
Create a Xapian::Database object indexing multiple files. 
 
unsigned timeout
A timeout value in milliseconds. 
 
include <sys/socket.h> with portability workarounds. 
 
Convert errno value to std::string, thread-safe if possible. 
 
Convert types to std::string. 
 
BackendManager subclass for remotetcp databases. 
 
Xapian::Database get_writable_database_as_database()
Create a Database object for the last opened WritableDatabase. 
 
This class provides read/write access to a database. 
 
include <sysexits.h> with portability workarounds. 
 
void errno_to_string(int e, string &s)
 
Database open(const std::string &host, unsigned int port, useconds_t timeout=10000, useconds_t connect_timeout=10000)
Construct a Database object for read-only access to a remote database accessed via a TCP connection...
 
Public interfaces for the Xapian library. 
 
string str(int value)
Convert int to std::string. 
 
Xapian::Database get_remote_database(const std::vector< std::string > &files, unsigned int timeout)
Create a RemoteTcp Xapian::Database with the specified timeout. 
 
Xapian::Database get_database_by_path(const std::string &path)
Get a RemoteTcp Xapian::Database instance of the database at path. 
 
include <windows.h> without all the bloat and damage. 
 
Xapian::WritableDatabase get_writable_database_again()
Create a WritableDatabase object for the last opened WritableDatabase. 
 
WritableDatabase open_writable(const std::string &host, unsigned int port, useconds_t timeout=0, useconds_t connect_timeout=10000, int flags=0)
Construct a WritableDatabase object for update access to a remote database accessed via a TCP connect...
 
void clean_up()
Called after each test, to perform any necessary cleanup. 
 
include <fcntl.h>, but working around broken platforms.