xapian-core  2.0.0
xapian-tcpsrv.cc
Go to the documentation of this file.
1 
4 /* Copyright 1999,2000,2001 BrightStation PLC
5  * Copyright 2001,2002 Ananova Ltd
6  * Copyright 2002,2003,2004,2006,2007,2008,2009,2010,2011,2013,2015,2023 Olly Betts
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, see
20  * <https://www.gnu.org/licenses/>.
21  */
22 
23 #include <config.h>
24 
25 #include <cstdlib>
26 
27 #include <iostream>
28 #include <string>
29 
30 #include "gnu_getopt.h"
31 
32 #include "xapian/constants.h"
33 #include "xapian/error.h"
34 #include "parseint.h"
35 #include "remotetcpserver.h"
36 #include "net/remoteserver.h"
37 #include "stringutils.h"
38 
39 using namespace std;
40 
42  Xapian::Registry reg;
43  // If you have defined your own weighting scheme, register it here
44  // like so:
45  // reg.register_weighting_scheme(FooWeight());
46  server.set_registry(reg);
47 }
48 
49 #define MSECS_IDLE_TIMEOUT_DEFAULT 60000
50 #define MSECS_ACTIVE_TIMEOUT_DEFAULT 15000
51 
52 #define PROG_NAME "xapian-tcpsrv"
53 #define PROG_DESC "TCP daemon for use with Xapian's remote backend"
54 
55 #define OPT_HELP 1
56 #define OPT_VERSION 2
57 
58 static const char * opts = "I:p:a:i:t:oqw";
59 static const struct option long_opts[] = {
60  {"interface", required_argument, 0, 'I'},
61  {"port", required_argument, 0, 'p'},
62  {"active-timeout", required_argument, 0, 'a'},
63  {"idle-timeout", required_argument, 0, 'i'},
64  {"timeout", required_argument, 0, 't'},
65  {"one-shot", no_argument, 0, 'o'},
66  {"quiet", no_argument, 0, 'q'},
67  {"writable", no_argument, 0, 'w'},
68  {"help", no_argument, 0, OPT_HELP},
69  {"version", no_argument, 0, OPT_VERSION},
70  {NULL, 0, 0, 0}
71 };
72 
73 static void show_usage() {
74  cout << "Usage: " PROG_NAME " [OPTIONS] DATABASE_PATH...\n\n"
75 "Options:\n"
76 " --port PORTNUM listen on port PORTNUM for connections (no default)\n"
77 " --interface ADDRESS listen on the interface associated with name or\n"
78 " address ADDRESS (default is all interfaces)\n"
79 " --idle-timeout MSECS set timeout for idle connections (default: "
81 " --active-timeout MSECS set timeout for active connections (default: "
83 " --timeout MSECS set both timeout values\n"
84 " --one-shot serve a single connection and exit\n"
85 " --quiet disable information messages to stdout\n"
86 " --writable allow updates\n"
87 " --help display this help and exit\n"
88 " --version output version information and exit\n";
89 }
90 
91 int main(int argc, char **argv) {
92  string host;
93  int port = 0;
94  double active_timeout = MSECS_ACTIVE_TIMEOUT_DEFAULT * 1e-3;
95  double idle_timeout = MSECS_IDLE_TIMEOUT_DEFAULT * 1e-3;
96 
97  bool one_shot = false;
98  bool verbose = true;
99  bool writable = false;
100  bool syntax_error = false;
101 
102  int c;
103  while ((c = gnu_getopt_long(argc, argv, opts, long_opts, NULL)) != -1) {
104  switch (c) {
105  case OPT_HELP:
106  cout << PROG_NAME " - " PROG_DESC "\n\n";
107  show_usage();
108  exit(0);
109  case OPT_VERSION:
110  cout << PROG_NAME " - " PACKAGE_STRING "\n";
111  exit(0);
112  case 'I':
113  host.assign(optarg);
114  break;
115  case 'p':
116  if (!parse_signed(optarg, port) ||
117  (port < 1 || port > 65535)) {
118  cerr << "Error: must specify a valid port number "
119  "(between 1 and 65535).\n";
120  exit(1);
121  }
122  break;
123  case 'a': {
124  unsigned int active;
125  if (!parse_unsigned(optarg, active)) {
126  cerr << "Active timeout must be >= 0\n";
127  exit(1);
128  }
129  active_timeout = active * 1e-3;
130  break;
131  }
132  case 'i': {
133  unsigned int idle;
134  if (!parse_unsigned(optarg, idle)) {
135  cerr << "Idle timeout must be >= 0\n";
136  exit(1);
137  }
138  idle_timeout = idle * 1e-3;
139  break;
140  }
141  case 't': {
142  unsigned int timeout;
143  if (!parse_unsigned(optarg, timeout)) {
144  cerr << "timeout must be >= 0\n";
145  exit(1);
146  }
147  active_timeout = idle_timeout = timeout * 1e-3;
148  break;
149  }
150  case 'o':
151  one_shot = true;
152  break;
153  case 'q':
154  verbose = false;
155  break;
156  case 'w':
157  writable = true;
158  break;
159  default:
160  syntax_error = true;
161  }
162  }
163 
164  if (syntax_error || argv[optind] == NULL) {
165  show_usage();
166  exit(1);
167  }
168 
169  if (port == 0) {
170  cerr << "Error: You must specify a port with --port\n";
171  exit(1);
172  }
173 
174  vector<string> dbnames(argv + optind, argv + argc);
175  try {
176  if (!one_shot) {
177  // Try to open the database(s) so we report problems now instead of
178  // waiting for the first connection.
179  for (auto& dbname : dbnames) {
180  if (writable) {
181  Xapian::WritableDatabase db(dbname,
183  } else {
184  Xapian::Database db(dbname);
185  }
186  }
187  }
188 
189  if (verbose) {
190  cout << "Starting";
191  if (writable)
192  cout << " writable";
193  cout << " server on";
194  if (!host.empty())
195  cout << " host " << host << ",";
196  cout << " port " << port << '\n';
197  }
198 
199  RemoteTcpServer server(dbnames, host, port, active_timeout,
200  idle_timeout, writable, verbose);
201 
202  if (verbose)
203  cout << "Listening...\n" << flush;
204 
206 
207  if (one_shot) {
208  server.run_once();
209  } else {
210  server.run();
211  }
212  } catch (const Xapian::Error &e) {
213  cerr << e.get_description() << '\n';
214  exit(1);
215  } catch (const exception &e) {
216  cerr << "Caught standard exception: " << e.what() << '\n';
217  exit(1);
218  } catch (...) {
219  cerr << "Caught unknown exception\n";
220  exit(1);
221  }
222 }
TCP/IP socket based server for RemoteDatabase.
void set_registry(const Xapian::Registry &reg_)
Set the registry used for (un)serialisation.
An indexed database of documents.
Definition: database.h:75
All exceptions thrown by Xapian are subclasses of Xapian::Error.
Definition: error.h:41
Registry for user subclasses.
Definition: registry.h:47
This class provides read/write access to a database.
Definition: database.h:964
#define PACKAGE_STRING
Definition: config.h:361
Constants in the Xapian namespace.
Hierarchy of classes which Xapian can throw as exceptions.
int optind
Definition: getopt.cc:93
char * optarg
Definition: getopt.cc:78
static const char * dbnames
Wrappers to allow GNU getopt to be used cleanly from C++ code.
#define no_argument
Definition: gnu_getopt.h:78
#define required_argument
Definition: gnu_getopt.h:79
int gnu_getopt_long(int argc_, char *const *argv_, const char *shortopts_, const struct option *longopts_, int *optind_)
Definition: gnu_getopt.h:96
const int DB_CREATE_OR_OPEN
Create database if it doesn't already exist.
Definition: constants.h:34
Parse signed and unsigned type from string and check for trailing characters.
bool parse_signed(const char *p, T &res)
Definition: parseint.h:44
bool parse_unsigned(const char *p, T &res)
Definition: parseint.h:29
Xapian remote backend server base class.
TCP/IP socket based server for RemoteDatabase.
Various handy string-related helpers.
#define STRINGIZE(X)
The STRINGIZE macro converts its parameter into a string constant.
Definition: stringutils.h:41
static int verbose
Definition: xapian-delve.cc:46
static const char * opts
static void show_usage()
#define OPT_VERSION
int main(int argc, char **argv)
#define PROG_NAME
#define MSECS_IDLE_TIMEOUT_DEFAULT
static const struct option long_opts[]
#define PROG_DESC
static void register_user_weighting_schemes(RemoteTcpServer &server)
#define OPT_HELP
#define MSECS_ACTIVE_TIMEOUT_DEFAULT