xapian-core  1.4.30
remoteconnection.h
Go to the documentation of this file.
1 
4 /* Copyright (C) 2006,2007,2008,2010,2011,2014,2015,2019,2024 Olly Betts
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #ifndef XAPIAN_INCLUDED_REMOTECONNECTION_H
22 #define XAPIAN_INCLUDED_REMOTECONNECTION_H
23 
24 #include <cerrno>
25 #include <string>
26 
27 #include "remoteprotocol.h"
28 #include "safenetdb.h" // For EAI_* constants.
29 #include "safeunistd.h"
30 
31 #ifdef __WIN32__
32 # include "safewinsock2.h"
33 
34 # include <xapian/error.h>
35 
49 struct WinsockInitializer {
50  WinsockInitializer() {
51  WSADATA wsadata;
52  int wsaerror = WSAStartup(MAKEWORD(2, 2), &wsadata);
53  // FIXME - should we check the returned information in wsadata to check
54  // that we have a version of winsock which is recent enough for us?
55 
56  if (wsaerror != 0) {
57  throw Xapian::NetworkError("Failed to initialize winsock", wsaerror);
58  }
59  }
60 
61  ~WinsockInitializer() {
62  WSACleanup();
63  }
64 };
65 
74 inline int socket_errno() {
75  int wsa_err = WSAGetLastError();
76  switch (wsa_err) {
77 # ifdef EADDRINUSE
78  case WSAEADDRINUSE: return EADDRINUSE;
79 # endif
80 # ifdef ETIMEDOUT
81  case WSAETIMEDOUT: return ETIMEDOUT;
82 # endif
83 # ifdef EINPROGRESS
84  case WSAEINPROGRESS: return EINPROGRESS;
85 # endif
86  default: return wsa_err;
87  }
88 }
89 
90 /* Newer compilers define these, in which case we map to those already defined
91  * values in socket_errno() above.
92  */
93 # ifndef EADDRINUSE
94 # define EADDRINUSE WSAEADDRINUSE
95 # endif
96 # ifndef ETIMEDOUT
97 # define ETIMEDOUT WSAETIMEDOUT
98 # endif
99 # ifndef EINPROGRESS
100 # define EINPROGRESS WSAEINPROGRESS
101 # endif
102 
103 // We must call closesocket() (instead of just close()) under __WIN32__ or
104 // else the socket remains in the CLOSE_WAIT state.
105 # define CLOSESOCKET(S) closesocket(S)
106 #else
107 # include "safesyssocket.h"
108 inline int socket_errno() { return errno; }
109 
110 # define CLOSESOCKET(S) close(S)
111 #endif
112 
113 inline int eai_to_xapian(int e) {
114  // Under WIN32, the EAI_* constants are defined to be WSA_* constants with
115  // roughly equivalent meanings, so we can just let them be handled as any
116  // other WSA_* error codes would be.
117 #ifndef __WIN32__
118  // Ensure they all have the same sign - this switch will fail to compile if
119  // we bitwise-or some 1 and some 2 bits to get 3.
120 #define C(X) ((X) < 0 ? 2 : 1)
121  // Switch on a value there is a case for, to avoid clang warning:
122  // "no case matching constant switch condition '0'"
123  switch (3) {
124  case
125  C(EAI_AGAIN)|
126  C(EAI_BADFLAGS)|
127  C(EAI_FAIL)|
128  C(EAI_FAMILY)|
129  C(EAI_MEMORY)|
130  C(EAI_NONAME)|
131  C(EAI_SERVICE)|
132  C(EAI_SOCKTYPE)|
133  C(EAI_SYSTEM)|
134 #ifdef EAI_ADDRFAMILY
135  // In RFC 2553 but not RFC 3493 or POSIX:
136  C(EAI_ADDRFAMILY)|
137 #endif
138 #ifdef EAI_NODATA
139  // In RFC 2553 but not RFC 3493 or POSIX:
140  C(EAI_NODATA)|
141 #endif
142 #ifdef EAI_OVERFLOW
143  // In RFC 3493 and POSIX but not RFC 2553:
144  C(EAI_OVERFLOW)|
145 #endif
146  0: break;
147  case 3: break;
148  }
149 #undef C
150 
151  // EAI_SYSTEM means "look at errno".
152  if (e == EAI_SYSTEM)
153  return errno;
154  // POSIX only says that EAI_* constants are "non-zero". On Linux they are
155  // negative, but allow for them being positive too.
156  if (EAI_FAIL > 0)
157  return -e;
158 #endif
159  return e;
160 }
161 
172 
175 
181  int fdin;
182 
189  int fdout;
190 
191 #ifndef __WIN32__
192  // On Unix-like platforms we want to avoid generating SIGPIPE when writing
193  // to a socket when the other end has been closed since signals break the
194  // encapsulation of what we're doing inside the library - either user code
195  // would need to handle the SIGPIPE, or we set a signal handler for SIGPIPE
196  // but that would handle *any* SIGPIPE in the process, not just those we
197  // might trigger, and that could break user code which expects to trigger
198  // and handle SIGPIPE.
199  //
200  // We don't need SIGPIPE since we can check errno==EPIPE instead (which is
201  // actually simpler to do).
202  //
203  // We support using SO_NOSIGPIPE (not standardised) or MSG_NOSIGNAL
204  // (specified by POSIX but more awkward to use) which seems to cover all
205  // modern Unix-like platforms. For platforms without either we currently
206  // just set the SIGPIPE signal handler to SIG_IGN.
207 # if defined(SO_NOSIGPIPE) && !defined(__NetBSD__)
208  // Prefer using SO_NOSIGPIPE and write(), except on NetBSD where we seem to
209  // still get SIGPIPE despite using it.
210 # define USE_SO_NOSIGPIPE
211 # elif defined MSG_NOSIGNAL
212  // Use send(..., MSG_NOSIGNAL).
213  int send_flags = MSG_NOSIGNAL;
214 # define USE_MSG_NOSIGNAL
215 # endif
216 #endif
217 
219  std::string buffer;
220 
223 
236  bool read_at_least(size_t min_len, double end_time);
237 
238 #ifdef __WIN32__
245  WSAOVERLAPPED overlapped;
246 
251  DWORD calc_read_wait_msecs(double end_time);
252 #else
254  ssize_t send_or_write(const void* p, size_t n);
255 #endif
256 
257  protected:
262  std::string context;
263 
264  public:
266  RemoteConnection(int fdin_, int fdout_,
267  const std::string & context_ = std::string());
268 
269 #ifdef __WIN32__
271  ~RemoteConnection();
272 #endif
273 
278  bool ready_to_read() const;
279 
297  int sniff_next_message_type(double end_time);
298 
309  int get_message(std::string &result, double end_time);
310 
327  int get_message_chunked(double end_time);
328 
349  int get_message_chunk(std::string &result, size_t at_least,
350  double end_time);
351 
363  int receive_file(const std::string &file, double end_time);
364 
374  void send_message(char type, const std::string & s, double end_time);
375 
385  void send_file(char type, int fd, double end_time);
386 
392  void shutdown();
393 
395  void do_close();
396 };
397 
404  public:
406  OwnedRemoteConnection(int fdin_, int fdout_,
407  const std::string& context_ = std::string())
408  : RemoteConnection(fdin_, fdout_, context_) { }
409 
412  do_close();
413  }
414 };
415 
416 #endif // XAPIAN_INCLUDED_REMOTECONNECTION_H
RemoteConnection which owns its own fd(s).
OwnedRemoteConnection(int fdin_, int fdout_, const std::string &context_=std::string())
Constructor.
~OwnedRemoteConnection()
Destructor.
A RemoteConnection object provides a bidirectional connection to another RemoteConnection object on a...
bool ready_to_read() const
See if there is data available to read.
int fdin
The file descriptor used for reading.
std::string buffer
Buffer to hold unprocessed input.
RemoteConnection(const RemoteConnection &)
Don't allow copying.
int get_message_chunk(std::string &result, size_t at_least, double end_time)
Read a chunk of a message from fdin.
void send_message(char type, const std::string &s, double end_time)
Send a message.
bool read_at_least(size_t min_len, double end_time)
Read until there are at least min_len bytes in buffer.
int fdout
The file descriptor used for writing.
int receive_file(const std::string &file, double end_time)
Save the contents of a message as a file.
off_t chunked_data_left
Remaining bytes of message data still to come over fdin for a chunked read.
void do_close()
Close the connection.
int get_message(std::string &result, double end_time)
Read one message from fdin.
void shutdown()
Shutdown the connection.
int sniff_next_message_type(double end_time)
Check what the next message type is.
int get_message_chunked(double end_time)
Prepare to read one message from fdin in chunks.
std::string context
The context to report with errors.
ssize_t send_or_write(const void *p, size_t n)
Helper which calls send() or write().
void operator=(const RemoteConnection &)
Don't allow assignment.
void send_file(char type, int fd, double end_time)
Send the contents of a file as a message.
Indicates a problem communicating with a remote database.
Definition: error.h:803
Hierarchy of classes which Xapian can throw as exceptions.
double end_time(double timeout)
Return the end time for a timeout in timeout seconds.
Definition: realtime.h:95
int eai_to_xapian(int e)
#define C(X)
int socket_errno()
Remote protocol version and message numbers.
include <netdb.h>, with portability workarounds.
include <sys/socket.h> with portability workarounds.
<unistd.h>, but with compat.
include <winsock2.h> but working around problems.