xapian-core  1.4.27
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 
171  void operator=(const RemoteConnection &);
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__
239 
245  WSAOVERLAPPED overlapped;
246 
251  DWORD calc_read_wait_msecs(double end_time);
252 #else
253 
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__
270  ~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
A RemoteConnection object provides a bidirectional connection to another RemoteConnection object on a...
OwnedRemoteConnection(int fdin_, int fdout_, const std::string &context_=std::string())
Constructor.
off_t chunked_data_left
Remaining bytes of message data still to come over fdin for a chunked read.
include <sys/socket.h> with portability workarounds.
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)
include <netdb.h>, with portability workarounds.
std::string context
The context to report with errors.
Remote protocol version and message numbers.
Hierarchy of classes which Xapian can throw as exceptions.
int fdin
The file descriptor used for reading.
include <winsock2.h> but working around problems.
std::string buffer
Buffer to hold unprocessed input.
RemoteConnection which owns its own fd(s).
~OwnedRemoteConnection()
Destructor.
Indicates a problem communicating with a remote database.
Definition: error.h:803
<unistd.h>, but with compat.
int fdout
The file descriptor used for writing.
int socket_errno()
#define C(X)