00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <config.h>
00024
00025 #include "tcpserver.h"
00026
00027 #include <xapian/error.h>
00028
00029 #include "safeerrno.h"
00030 #include "safefcntl.h"
00031
00032 #include "noreturn.h"
00033 #include "remoteconnection.h"
00034 #include "utils.h"
00035
00036 #ifdef __WIN32__
00037 # include <process.h>
00038 #else
00039 # include <sys/socket.h>
00040 # include <netinet/in_systm.h>
00041 # include <netinet/in.h>
00042 # include <netinet/ip.h>
00043 # include <netinet/tcp.h>
00044 # include <arpa/inet.h>
00045 # include <netdb.h>
00046 # include <signal.h>
00047 # include <sys/wait.h>
00048 #endif
00049
00050 #include <iostream>
00051
00052 #include <cstring>
00053 #include <cstdio>
00054 #include <sys/types.h>
00055
00056 using namespace std;
00057
00058
00059 #if !defined SIGCHLD && defined SIGCLD
00060 # define SIGCHLD SIGCLD
00061 #endif
00062
00063 #ifdef __WIN32__
00064
00065
00066 # define CLOSESOCKET(S) closesocket(S)
00067 #else
00068 # define CLOSESOCKET(S) close(S)
00069 #endif
00070
00072 TcpServer::TcpServer(const std::string & host, int port, bool tcp_nodelay,
00073 bool verbose_)
00074 :
00075 #if defined __CYGWIN__ || defined __WIN32__
00076 mutex(NULL),
00077 #endif
00078 listen_socket(get_listening_socket(host, port, tcp_nodelay
00079 #if defined __CYGWIN__ || defined __WIN32__
00080 , mutex
00081 #endif
00082 )),
00083 verbose(verbose_)
00084 {
00085 }
00086
00087 int
00088 TcpServer::get_listening_socket(const std::string & host, int port,
00089 bool tcp_nodelay
00090 #if defined __CYGWIN__ || defined __WIN32__
00091 , HANDLE &mutex
00092 #endif
00093 )
00094 {
00095 int socketfd = socket(PF_INET, SOCK_STREAM, 0);
00096
00097 if (socketfd < 0) {
00098 throw Xapian::NetworkError("socket", socket_errno());
00099 }
00100
00101 int retval = 0;
00102
00103 if (tcp_nodelay) {
00104 int optval = 1;
00105
00106
00107 retval = setsockopt(socketfd, IPPROTO_TCP, TCP_NODELAY,
00108 reinterpret_cast<char *>(&optval),
00109 sizeof(optval));
00110 }
00111
00112 {
00113 int optval = 1;
00114 #if defined __CYGWIN__ || defined __WIN32__
00115
00116
00117
00118
00119
00120
00121 char name[64];
00122 sprintf(name, "Global\\xapian-tcpserver-listening-%d", port);
00123 if ((mutex = CreateMutex(NULL, TRUE, name)) == NULL) {
00124
00125
00126
00127 } else if (GetLastError() == ERROR_ALREADY_EXISTS) {
00128
00129
00130 CloseHandle(mutex);
00131 mutex = NULL;
00132 }
00133 if (mutex == NULL) {
00134 cerr << "Server is already running on port " << port << endl;
00135
00136
00137 exit(69);
00138 }
00139 #endif
00140 if (retval >= 0) {
00141 retval = setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,
00142 reinterpret_cast<char *>(&optval),
00143 sizeof(optval));
00144 }
00145
00146 #if defined SO_EXCLUSIVEADDRUSE
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 if (retval >= 0) {
00157 (void)setsockopt(socketfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
00158 reinterpret_cast<char *>(&optval),
00159 sizeof(optval));
00160 }
00161 #endif
00162 }
00163
00164 if (retval < 0) {
00165 int saved_errno = socket_errno();
00166 CLOSESOCKET(socketfd);
00167 throw Xapian::NetworkError("setsockopt failed", saved_errno);
00168 }
00169
00170 struct sockaddr_in addr;
00171 memset(&addr, 0, sizeof(addr));
00172 addr.sin_family = AF_INET;
00173 addr.sin_port = htons(port);
00174 if (host.empty()) {
00175 addr.sin_addr.s_addr = INADDR_ANY;
00176 } else {
00177
00178 struct hostent *hostent = gethostbyname(host.c_str());
00179
00180 if (hostent == 0) {
00181 throw Xapian::NetworkError(string("Couldn't resolve host ") + host,
00182 #ifdef __WIN32__
00183 socket_errno()
00184 #else
00185
00186
00187
00188
00189
00190 (h_errno < 0 ? errno : -h_errno)
00191 #endif
00192 );
00193 }
00194
00195 memcpy(&addr.sin_addr, hostent->h_addr, hostent->h_length);
00196 }
00197
00198 retval = bind(socketfd,
00199 reinterpret_cast<sockaddr *>(&addr),
00200 sizeof(addr));
00201
00202 if (retval < 0) {
00203 int saved_errno = socket_errno();
00204 if (saved_errno == EADDRINUSE) {
00205 cerr << host << ':' << port << " already in use" << endl;
00206
00207
00208 exit(69);
00209 }
00210 if (saved_errno == EACCES) {
00211 cerr << "Can't bind to privileged port " << port << endl;
00212
00213
00214 exit(77);
00215 }
00216 CLOSESOCKET(socketfd);
00217 throw Xapian::NetworkError("bind failed", saved_errno);
00218 }
00219
00220 retval = listen(socketfd, 5);
00221
00222 if (retval < 0) {
00223 int saved_errno = socket_errno();
00224 CLOSESOCKET(socketfd);
00225 throw Xapian::NetworkError("listen failed", saved_errno);
00226 }
00227 return socketfd;
00228 }
00229
00230 int
00231 TcpServer::accept_connection()
00232 {
00233 struct sockaddr_in remote_address;
00234 SOCKLEN_T remote_address_size = sizeof(remote_address);
00235
00236 int con_socket = accept(listen_socket,
00237 reinterpret_cast<sockaddr *>(&remote_address),
00238 &remote_address_size);
00239
00240 if (con_socket < 0) {
00241 #ifdef __WIN32__
00242 if (WSAGetLastError() == WSAEINTR) {
00243
00244 if (mutex) CloseHandle(mutex);
00245 mutex = NULL;
00246 return -1;
00247 }
00248 #endif
00249 throw Xapian::NetworkError("accept failed", socket_errno());
00250 }
00251
00252 if (remote_address_size != sizeof(remote_address)) {
00253 throw Xapian::NetworkError("accept: unexpected remote address size");
00254 }
00255
00256 if (verbose) {
00257 cout << "Connection from " << inet_ntoa(remote_address.sin_addr)
00258 << ", port " << remote_address.sin_port << endl;
00259 }
00260
00261 return con_socket;
00262 }
00263
00264 TcpServer::~TcpServer()
00265 {
00266 CLOSESOCKET(listen_socket);
00267 #if defined __CYGWIN__ || defined __WIN32__
00268 if (mutex) CloseHandle(mutex);
00269 #endif
00270 }
00271
00272 #ifdef HAVE_FORK
00273
00274 void
00275 TcpServer::run_once()
00276 {
00277 int connected_socket = accept_connection();
00278 pid_t pid = fork();
00279 if (pid == 0) {
00280
00281 close(listen_socket);
00282
00283 handle_one_connection(connected_socket);
00284 close(connected_socket);
00285
00286 if (verbose) cout << "Closing connection." << endl;
00287 exit(0);
00288 }
00289
00290
00291
00292 if (pid < 0) {
00293
00294 int saved_errno = socket_errno();
00295 close(connected_socket);
00296 throw Xapian::NetworkError("fork failed", saved_errno);
00297 }
00298
00299 close(connected_socket);
00300 }
00301
00302 extern "C" {
00303
00304 XAPIAN_NORETURN(static void on_SIGTERM(int ));
00305
00306 static void
00307 on_SIGTERM(int )
00308 {
00309 signal(SIGTERM, SIG_DFL);
00310
00311 #ifdef HAVE_KILLPG
00312 killpg(0, SIGTERM);
00313 #else
00314 kill(0, SIGTERM);
00315 #endif
00316 exit(0);
00317 }
00318
00319 #ifdef HAVE_WAITPID
00320 static void
00321 on_SIGCHLD(int )
00322 {
00323 int status;
00324 while (waitpid(-1, &status, WNOHANG) > 0);
00325 }
00326 #endif
00327
00328 }
00329
00330 void
00331 TcpServer::run()
00332 {
00333
00334
00335
00336 #ifdef HAVE_WAITPID
00337 signal(SIGCHLD, on_SIGCHLD);
00338 #else
00339 signal(SIGCHLD, SIG_IGN);
00340 #endif
00341 signal(SIGTERM, on_SIGTERM);
00342
00343 while (true) {
00344 try {
00345 run_once();
00346 } catch (const Xapian::Error &e) {
00347
00348 cerr << "Caught " << e.get_description() << endl;
00349 } catch (...) {
00350
00351 cerr << "Caught exception." << endl;
00352 }
00353 }
00354 }
00355
00356 #elif defined __WIN32__
00357
00358
00359
00364 static const int *pShutdownSocket = NULL;
00365
00367 static BOOL
00368 CtrlHandler(DWORD fdwCtrlType)
00369 {
00370 switch (fdwCtrlType) {
00371 case CTRL_C_EVENT:
00372 case CTRL_CLOSE_EVENT:
00373
00374
00375
00376 case CTRL_LOGOFF_EVENT:
00377 case CTRL_SHUTDOWN_EVENT:
00378
00379
00380
00381 cout << "Shutting down..." << endl;
00382 break;
00383 case CTRL_BREAK_EVENT:
00384
00385
00386
00387 cout << "Ctrl+Break: aborting process" << endl;
00388 return FALSE;
00389 default:
00390 cerr << "unexpected CtrlHandler: " << fdwCtrlType << endl;
00391 return FALSE;
00392 }
00393
00394
00395
00396
00397 if (!pShutdownSocket || closesocket(*pShutdownSocket) == SOCKET_ERROR) {
00398
00399
00400 return FALSE;
00401 }
00402
00403 pShutdownSocket = NULL;
00404 return TRUE;
00405 }
00406
00408 struct thread_param
00409 {
00410 thread_param(TcpServer *s, int c) : server(s), connected_socket(c) {}
00411 TcpServer *server;
00412 int connected_socket;
00413 };
00414
00416 static unsigned __stdcall
00417 run_thread(void * param_)
00418 {
00419 thread_param * param(reinterpret_cast<thread_param *>(param_));
00420 int socket = param->connected_socket;
00421
00422 param->server->handle_one_connection(socket);
00423 closesocket(socket);
00424
00425 delete param;
00426
00427 _endthreadex(0);
00428 return 0;
00429 }
00430
00431 void
00432 TcpServer::run()
00433 {
00434
00435
00436
00437
00438 pShutdownSocket = &listen_socket;
00439 if (!::SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE))
00440 throw Xapian::NetworkError("Failed to install shutdown handler");
00441
00442 while (true) {
00443 try {
00444 int connected_socket = accept_connection();
00445 if (connected_socket == -1)
00446 return;
00447
00448
00449
00450
00451
00452 thread_param *param = new thread_param(this, connected_socket);
00453 HANDLE hthread = (HANDLE)_beginthreadex(NULL, 0, ::run_thread, param, 0, NULL);
00454 if (hthread == 0) {
00455
00456
00457 closesocket(connected_socket);
00458 throw Xapian::NetworkError("_beginthreadex failed", errno);
00459 }
00460
00461
00462
00463
00464
00465 CloseHandle(hthread);
00466 } catch (const Xapian::Error &e) {
00467
00468 cerr << "Caught " << e.get_description() << endl;
00469 } catch (...) {
00470
00471 cerr << "Caught exception." << endl;
00472 }
00473 }
00474 }
00475
00476 void
00477 TcpServer::run_once()
00478 {
00479
00480 int fd = accept_connection();
00481 handle_one_connection(fd);
00482 closesocket(fd);
00483 }
00484
00485 #else
00486 # error Neither HAVE_FORK nor __WIN32__ are defined.
00487 #endif