Update .gitignore
[xapian.git] / xapian-core / bin / xapian-tcpsrv.cc
blob92f01e021d46ba2b11593a1f5a708b348436d2a4
1 /* xapian-tcpsrv.cc: tcp daemon for use with Xapian's remote backend
3 * Copyright 1999,2000,2001 BrightStation PLC
4 * Copyright 2001,2002 Ananova Ltd
5 * Copyright 2002,2003,2004,2006,2007,2008,2009,2010,2011,2013,2015 Olly Betts
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA
23 #include <config.h>
25 #include <cstdlib>
27 #include "safeerrno.h"
29 #include <iostream>
30 #include <string>
32 #include "gnu_getopt.h"
34 #include "xapian/constants.h"
35 #include "xapian/error.h"
36 #include "net/remotetcpserver.h"
37 #include "net/remoteserver.h"
38 #include "stringutils.h"
40 using namespace std;
42 static void register_user_weighting_schemes(RemoteTcpServer &server) {
43 Xapian::Registry reg;
44 // If you have defined your own weighting scheme, register it here
45 // like so:
46 // reg.register_weighting_scheme(FooWeight());
47 server.set_registry(reg);
50 const int MSECS_IDLE_TIMEOUT_DEFAULT = 60000;
51 const int MSECS_ACTIVE_TIMEOUT_DEFAULT = 15000;
53 #define PROG_NAME "xapian-tcpsrv"
54 #define PROG_DESC "TCP daemon for use with Xapian's remote backend"
56 #define OPT_HELP 1
57 #define OPT_VERSION 2
59 static const char * opts = "I:p:a:i:t:oqw";
60 static const struct option long_opts[] = {
61 {"interface", required_argument, 0, 'I'},
62 {"port", required_argument, 0, 'p'},
63 {"active-timeout", required_argument, 0, 'a'},
64 {"idle-timeout", required_argument, 0, 'i'},
65 {"timeout", required_argument, 0, 't'},
66 {"one-shot", no_argument, 0, 'o'},
67 {"quiet", no_argument, 0, 'q'},
68 {"writable", no_argument, 0, 'w'},
69 {"help", no_argument, 0, OPT_HELP},
70 {"version", no_argument, 0, OPT_VERSION},
71 {NULL, 0, 0, 0}
74 static void show_usage() {
75 cout << "Usage: " PROG_NAME " [OPTIONS] DATABASE_DIRECTORY...\n\n"
76 "Options:\n"
77 " --port PORTNUM listen on port PORTNUM for connections (no default)\n"
78 " --interface ADDRESS listen on the interface associated with name or\n"
79 " address ADDRESS (default is all interfaces)\n"
80 " --idle-timeout MSECS set timeout for idle connections (default " STRINGIZE(MSECS_IDLE_TIMEOUT_DEFAULT) "ms)\n"
81 " --active-timeout MSECS set timeout for active connections (default " STRINGIZE(MSECS_ACTIVE_TIMEOUT_DEFAULT) "ms)\n"
82 " --timeout MSECS set both timeout values\n"
83 " --one-shot serve a single connection and exit\n"
84 " --quiet disable information messages to stdout\n"
85 " --writable allow updates (only one database directory allowed)\n"
86 " --help display this help and exit\n"
87 " --version output version information and exit" << endl;
90 int main(int argc, char **argv) {
91 string host;
92 int port = 0;
93 double active_timeout = MSECS_ACTIVE_TIMEOUT_DEFAULT * 1e-3;
94 double idle_timeout = MSECS_IDLE_TIMEOUT_DEFAULT * 1e-3;
96 bool one_shot = false;
97 bool verbose = true;
98 bool writable = false;
99 bool syntax_error = false;
101 int c;
102 while ((c = gnu_getopt_long(argc, argv, opts, long_opts, NULL)) != -1) {
103 switch (c) {
104 case OPT_HELP:
105 cout << PROG_NAME " - " PROG_DESC "\n\n";
106 show_usage();
107 exit(0);
108 case OPT_VERSION:
109 cout << PROG_NAME " - " PACKAGE_STRING << endl;
110 exit(0);
111 case 'I':
112 host.assign(optarg);
113 break;
114 case 'p':
115 port = atoi(optarg);
116 if (port <= 0 || port >= 65536) {
117 cerr << "Error: must specify a valid port number "
118 "(between 1 and 65535). "
119 "We actually got " << port << endl;
120 exit(1);
122 break;
123 case 'a':
124 active_timeout = atoi(optarg) * 1e-3;
125 break;
126 case 'i':
127 idle_timeout = atoi(optarg) * 1e-3;
128 break;
129 case 't':
130 active_timeout = idle_timeout = atoi(optarg) * 1e-3;
131 break;
132 case 'o':
133 one_shot = true;
134 break;
135 case 'q':
136 verbose = false;
137 break;
138 case 'w':
139 writable = true;
140 break;
141 default:
142 syntax_error = true;
146 if (syntax_error || argv[optind] == NULL) {
147 show_usage();
148 exit(1);
151 if (port == 0) {
152 cerr << "Error: You must specify a port with --port" << endl;
153 exit(1);
156 if (writable && (argc - optind) != 1) {
157 cerr << "Error: only one database directory allowed with '--writable'." << endl;
158 exit(1);
161 try {
162 vector<string> dbnames;
163 // Try to open the database(s) so we report problems now instead of
164 // waiting for the first connection.
165 if (writable) {
166 Xapian::WritableDatabase db(argv[optind], Xapian::DB_CREATE_OR_OPEN);
167 dbnames.push_back(argv[optind]);
168 } else {
169 while (argv[optind]) {
170 dbnames.push_back(argv[optind]);
171 Xapian::Database db(argv[optind++]);
175 if (verbose) {
176 cout << "Starting";
177 if (writable)
178 cout << " writable";
179 cout << " server on";
180 if (!host.empty())
181 cout << " host " << host << ",";
182 cout << " port " << port << endl;
185 RemoteTcpServer server(dbnames, host, port, active_timeout,
186 idle_timeout, writable, verbose);
188 if (verbose)
189 cout << "Listening..." << endl;
191 register_user_weighting_schemes(server);
193 if (one_shot) {
194 server.run_once();
195 } else {
196 server.run();
198 } catch (const Xapian::Error &e) {
199 cerr << e.get_description() << endl;
200 exit(1);
201 } catch (const exception &e) {
202 cerr << "Caught standard exception: " << e.what() << endl;
203 exit(1);
204 } catch (...) {
205 cerr << "Caught unknown exception" << endl;
206 exit(1);