43 # include <netinet/in_systm.h> 44 # include <netinet/in.h> 45 # include <netinet/ip.h> 46 # include <netinet/tcp.h> 47 # include <arpa/inet.h> 49 # include <sys/wait.h> 57 #include <sys/types.h> 62 #if !defined SIGCHLD && defined SIGCLD 63 # define SIGCHLD SIGCLD 69 # define CLOSESOCKET(S) closesocket(S) 71 # define CLOSESOCKET(S) close(S) 75 TcpServer::TcpServer(
const std::string & host,
int port,
bool tcp_nodelay,
77 : listen_socket(get_listening_socket(host, port, tcp_nodelay
78 #
if defined __CYGWIN__ || defined __WIN32__
87 TcpServer::get_listening_socket(
const std::string & host,
int port,
89 #
if defined __CYGWIN__ || defined __WIN32__
96 for (
auto&& r :
Resolver(host, port, AI_PASSIVE)) {
98 int fd = socket(r.ai_family, socktype, r.ai_protocol);
102 #if !defined __WIN32__ && defined F_SETFD && defined FD_CLOEXEC 107 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
117 retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
118 reinterpret_cast<char *>(&optval),
123 #if defined __CYGWIN__ || defined __WIN32__ 130 string name =
"Global\\xapian-tcpserver-listening-" +
str(port);
131 if ((mutex = CreateMutex(NULL, TRUE, name.c_str())) == NULL) {
135 }
else if (GetLastError() == ERROR_ALREADY_EXISTS) {
142 cerr <<
"Server is already running on port " << port << endl;
149 retval = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
150 reinterpret_cast<char *>(&optval),
160 if (::bind(fd, r.ai_addr, r.ai_addrlen) == 0) {
174 if (socketfd == -1) {
175 if (bind_errno == EADDRINUSE) {
176 cerr << host <<
':' << port <<
" already in use" << endl;
181 if (bind_errno == EACCES) {
182 cerr <<
"Can't bind to privileged port " << port << endl;
190 if (listen(socketfd, 5) < 0) {
199 TcpServer::accept_connection()
201 struct sockaddr_in remote_address;
202 SOCKLEN_T remote_address_size =
sizeof(remote_address);
204 int con_socket = accept(listen_socket,
205 reinterpret_cast<sockaddr *>(&remote_address),
206 &remote_address_size);
208 if (con_socket < 0) {
210 if (WSAGetLastError() == WSAEINTR) {
212 if (mutex) CloseHandle(mutex);
220 if (remote_address_size !=
sizeof(remote_address)) {
225 char buf[INET_ADDRSTRLEN];
230 void * src = &remote_address.sin_addr;
231 const char * r = inet_ntop(AF_INET, src, buf,
sizeof(buf));
237 DWORD size =
sizeof(buf);
238 if (WSAAddressToString(reinterpret_cast<sockaddr*>(&remote_address),
239 sizeof(remote_address), NULL, buf, &size) != 0) {
243 const char * r = buf;
245 int port = remote_address.sin_port;
246 cout <<
"Connection from " << r <<
", port " << port << endl;
252 TcpServer::~TcpServer()
255 #if defined __CYGWIN__ || defined __WIN32__ 256 if (mutex) CloseHandle(mutex);
265 XAPIAN_NORETURN(
static void on_SIGTERM(
int ));
270 signal(SIGTERM, SIG_DFL);
285 while (waitpid(-1, &status, WNOHANG) > 0);
298 signal(SIGCHLD, on_SIGCHLD);
300 signal(SIGCHLD, SIG_IGN);
302 signal(SIGTERM, on_SIGTERM);
306 int connected_socket = accept_connection();
310 close(listen_socket);
312 handle_one_connection(connected_socket);
313 close(connected_socket);
315 if (
verbose) cout <<
"Connection closed." << endl;
326 close(connected_socket);
330 close(connected_socket);
336 cerr <<
"Caught exception." << endl;
341 #elif defined __WIN32__ 349 static const int *pShutdownSocket = NULL;
353 CtrlHandler(DWORD fdwCtrlType)
355 switch (fdwCtrlType) {
357 case CTRL_CLOSE_EVENT:
361 case CTRL_LOGOFF_EVENT:
362 case CTRL_SHUTDOWN_EVENT:
366 cout <<
"Shutting down..." << endl;
368 case CTRL_BREAK_EVENT:
372 cout <<
"Ctrl+Break: aborting process" << endl;
375 cerr <<
"unexpected CtrlHandler: " << fdwCtrlType << endl;
382 if (!pShutdownSocket || closesocket(*pShutdownSocket) == SOCKET_ERROR) {
388 pShutdownSocket = NULL;
395 thread_param(TcpServer *s,
int c) : server(s), connected_socket(c) {}
397 int connected_socket;
401 static unsigned __stdcall
402 run_thread(
void * param_)
404 thread_param * param(reinterpret_cast<thread_param *>(param_));
405 int socket = param->connected_socket;
407 param->server->handle_one_connection(socket);
423 pShutdownSocket = &listen_socket;
424 if (!::SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE))
429 int connected_socket = accept_connection();
430 if (connected_socket == -1)
437 thread_param *param =
new thread_param(
this, connected_socket);
438 HANDLE hthread = (HANDLE)_beginthreadex(NULL, 0, ::run_thread, param, 0, NULL);
442 closesocket(connected_socket);
450 CloseHandle(hthread);
456 cerr <<
"Caught exception." << endl;
462 # error Neither HAVE_FORK nor __WIN32__ are defined. 466 TcpServer::run_once()
469 int fd = accept_connection();
470 handle_one_connection(fd);
Define the XAPIAN_NORETURN macro.
RemoteConnection class used by the remote backend.
include <sys/socket.h> with portability workarounds.
Convert types to std::string.
include <netdb.h>, with portability workarounds.
Hierarchy of classes which Xapian can throw as exceptions.
include <sysexits.h> with portability workarounds.
Resolve hostnames and ip addresses.
string str(int value)
Convert int to std::string.
std::string get_description() const
Return a string describing this object.
All exceptions thrown by Xapian are subclasses of Xapian::Error.
Indicates a problem communicating with a remote database.
Generic TCP/IP socket based server base class.
if(!(properties &BACKEND))
include <fcntl.h>, but working around broken platforms.