socketsession.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef __SOCKETSESSION_H_
  15. #define __SOCKETSESSION_H_ 1
  16. #include <boost/noncopyable.hpp>
  17. #include <exceptions/exceptions.h>
  18. #include <string>
  19. #include <sys/socket.h>
  20. namespace isc {
  21. namespace util {
  22. namespace io {
  23. /// \page SocketSessionUtility Socket session utility
  24. ///
  25. /// This utility defines a set of classes that support forwarding a
  26. /// "socket session" from one process to another. A socket session is a
  27. /// conceptual tuple of the following elements:
  28. /// - A network socket
  29. /// - The local and remote endpoints of a (IP) communication taking place on
  30. /// the socket. In practice an endpoint is a pair of an IP address and
  31. /// TCP or UDP port number.
  32. /// - Some amount of data sent from the remote endpoint and received on the
  33. /// socket. We call it (socket) session data in this documentation.
  34. ///
  35. /// Note that this is a conceptual definition. Depending on the underlying
  36. /// implementation and/or the network protocol, some of the elements could be
  37. /// part of others; for example, if it's an established TCP connection,
  38. /// the local and remote endpoints would be able to be retrieved from the
  39. /// socket using the standard \c getsockname() and \c getpeername() system
  40. /// calls. But in this definition we separate these to be more generic.
  41. /// Also, as a matter of fact our intended usage includes non-connected UDP
  42. /// communications, in which case at least the remote endpoint should be
  43. /// provided separately from the socket.
  44. ///
  45. /// In the actual implementation we represent a socket as a tuple of
  46. /// socket's file descriptor, address family (e.g. \c AF_INET6),
  47. /// socket type (e.g. \c SOCK_STREAM), and protocol (e.g. \c IPPROTO_TCP).
  48. /// The latter three are included in the representation of a socket in order
  49. /// to provide complete information of how the socket would be created
  50. /// by the \c socket(2) system call. More specifically in practice, these
  51. /// parameters could be used to construct a Python socket object from the
  52. /// file descriptor.
  53. ///
  54. /// We use the standard \c sockaddr structure to represent endpoints.
  55. ///
  56. /// Socket session data is an opaque memory region of an arbitrary length
  57. /// (possibly with some reasonable upper limit).
  58. ///
  59. /// To forward a socket session between processes, we use connected UNIX
  60. /// domain sockets established between the processes. The file descriptor
  61. /// will be forwarded through the sockets as an ancillary data item of
  62. /// type \c SCM_RIGHTS. Other elements of the session will be transferred
  63. /// as normal data over the connection.
  64. ///
  65. /// We provide three classes to help applications forward socket sessions:
  66. /// \c SocketSessionForwarder is the sender of the UNIX domain connection,
  67. /// while \c SocketSessionReceiver is the receiver (this interface assumes
  68. /// one direction of forwarding); \c SocketSession represents a single
  69. /// socket session.
  70. ///
  71. /// \c SocketSessionForwarder and \c SocketSessionReceiver objects use a
  72. /// straightforward protocol to pass elements of socket sessions.
  73. /// Once the connection is established, the forwarder object first forwards
  74. /// the file descriptor with 1-byte dummy data. It then forwards a
  75. /// "(socket) session header", which contains all other elements of the session
  76. /// except the file descriptor (already forwarded) and session data.
  77. /// The wire format of the header is as follows:
  78. /// - The length of the header (16-bit unsigned integer)
  79. /// - Address family
  80. /// - Socket type
  81. /// - Protocol
  82. /// - Size of the local endpoint in bytes
  83. /// - Local endpoint (a copy of the memory image of the corresponding
  84. /// \c sockaddr)
  85. /// - Size of the remote endpoint in bytes
  86. /// - Remote endpoint (same as local endpoint)
  87. /// - Size of session data in bytes
  88. ///
  89. /// The type of the fields is 32-bit unsigned integer unless explicitly
  90. /// noted, and all fields are formatted in the network byte order.
  91. ///
  92. /// The socket session data immediately follows the session header.
  93. ///
  94. /// Note that the fields do not necessarily be in the network byte order
  95. /// because they are expected to be exchanged on the same machine. Likewise,
  96. /// integer elements such as address family do not necessarily be represented
  97. /// as an fixed-size value (i.e., 32-bit). But fixed size fields are used
  98. /// in order to ensure maximum portability in such a (rare) case where the
  99. /// forwarder and the receiver are built with different compilers that have
  100. /// different definitions of \c int. Also, since \c sockaddr fields are
  101. /// generally formatted in the network byte order, other fields are defined
  102. /// so to be consistent.
  103. ///
  104. /// One basic assumption in the API of this utility is socket sessions should
  105. /// be forwarded without blocking, thus eliminating the need for incremental
  106. /// read/write or blocking other important services such as responding to
  107. /// requests from the application's clients. This assumption should be held
  108. /// as long as both the forwarder and receiver have sufficient resources
  109. /// to handle the forwarding process since the communication is local.
  110. /// But a forward attempt could still block if the receiver is busy (or even
  111. /// hang up) and cannot keep up with the volume of incoming sessions.
  112. ///
  113. /// So, in this implementation, the forwarder uses non blocking writes to
  114. /// forward sessions. If a write attempt could block, it immediately gives
  115. /// up the operation with an exception. The corresponding application is
  116. /// expected to catch it, close the connection, and perform any necessary
  117. /// recovery for that application (that would normally be re-establish the
  118. /// connection with a new receiver, possibly after confirming the receiving
  119. /// side is still alive). On the other hand, the receiver implementation
  120. /// assumes it's possible that it only receive incomplete elements of a
  121. /// session (such as in the case where the forwarder writes part of the
  122. /// entire session and gives up the connection). The receiver implementation
  123. /// throws an exception when it encounters an incomplete session. Like the
  124. /// case of the forwarder application, the receiver application is expected
  125. /// to catch it, close the connection, and perform any necessary recovery
  126. /// steps.
  127. ///
  128. /// Note that the receiver implementation uses blocking read. So it's
  129. /// application's responsibility to ensure that there's at least some data
  130. /// in the connection when the receiver object is requested to receive a
  131. /// session (unless this operation can be blocking, e.g., by the use of
  132. /// a separate thread). Also, if the forwarder implementation or application
  133. /// is malicious or extremely buggy and intentionally sends partial session
  134. /// and keeps the connection, the receiver could block in receiving a session.
  135. /// In general, we assume the forwarder doesn't do intentional blocking
  136. /// as it's a local node and is generally a module of the same (BIND 10)
  137. /// system. The minimum requirement for the forwarder implementation (and
  138. /// application) is to make sure the connection is closed once it detects
  139. /// an error on it. Even a naive implementation that simply dies due to
  140. /// the exception will meet this requirement.
  141. /// An exception indicating general errors that takes place in the
  142. /// socket session related class objects.
  143. ///
  144. /// In general the errors are unusual but possible failures such as unexpected
  145. /// connection reset, and suggest the application to close the connection and
  146. /// (if necessary) reestablish it.
  147. class SocketSessionError: public Exception {
  148. public:
  149. SocketSessionError(const char *file, size_t line, const char *what):
  150. isc::Exception(file, line, what) {}
  151. };
  152. /// The "base" class of \c SocketSessionForwarder
  153. ///
  154. /// This class defines abstract interfaces of the \c SocketSessionForwarder
  155. /// class. Although \c SocketSessionForwarder is not intended to be used in
  156. /// a polymorphic way, it's not easy to use in tests because it will require
  157. /// various low level network operations. So it would be useful if we
  158. /// provide a framework for defining a fake or mock version of it.
  159. /// An application that needs to use \c SocketSessionForwarder would actually
  160. /// refer to this base class, and tests for the application would define
  161. /// and use a fake version of the forwarder class.
  162. ///
  163. /// Normal applications are not expected to define and use their own derived
  164. /// version of this base class, while it's not prohibited at the API level.
  165. ///
  166. /// See description of \c SocketSessionForwarder for the expected interface.
  167. class BaseSocketSessionForwarder {
  168. protected:
  169. BaseSocketSessionForwarder() {}
  170. public:
  171. virtual ~BaseSocketSessionForwarder() {}
  172. virtual void connectToReceiver() = 0;
  173. virtual void close() = 0;
  174. virtual void push(int sock, int family, int type, int protocol,
  175. const struct sockaddr& local_end,
  176. const struct sockaddr& remote_end,
  177. const void* data, size_t data_len) = 0;
  178. };
  179. /// The forwarder of socket sessions
  180. ///
  181. /// An object of this class maintains a UNIX domain socket (normally expected
  182. /// to be connected to a \c SocketSessionReceiver object) and forwards
  183. /// socket sessions to the receiver.
  184. ///
  185. /// See the description of \ref SocketSessionUtility for other details of how
  186. /// the session forwarding works.
  187. class SocketSessionForwarder : boost::noncopyable,
  188. public BaseSocketSessionForwarder
  189. {
  190. public:
  191. /// The constructor.
  192. ///
  193. /// It's constructed with path information of the intended receiver,
  194. /// but does not immediately establish a connection to the receiver;
  195. /// \c connectToReceiver() must be called to establish it. These are
  196. /// separated so that an object of class can be initialized (possibly
  197. /// as an attribute of a higher level application class object) without
  198. /// knowing the receiver is ready for accepting new forwarders. The
  199. /// separate connect interface allows the object to be reused when it
  200. /// detects connection failure and tries to re-establish it after closing
  201. /// the failed one.
  202. ///
  203. /// On construction, it also installs a signal filter for SIGPIPE to
  204. /// ignore it. Since this class uses a stream-type connected UNIX domain
  205. /// socket, if the receiver (abruptly) closes the connection a subsequent
  206. /// write operation on the socket would trigger a SIGPIPE signal, which
  207. /// kills the caller process by default. This behavior would be
  208. /// undesirable in many cases, so this implementation always disables
  209. /// the signal.
  210. ///
  211. /// This approach has some drawbacks, however; first, since signal handling
  212. /// is process (or thread) wide, ignoring it may not what the application
  213. /// wants. On the other hand, if the application changes how the signal is
  214. /// handled after instantiating this class, the new behavior affects the
  215. /// class operation. Secondly, even if ignoring the signal is the desired
  216. /// operation, it's a waste to set the filter every time this class object
  217. /// is constructed. It's sufficient to do it once. We still adopt this
  218. /// behavior based on the observation that in most cases applications would
  219. /// like to ignore SIGPIPE (or simply doesn't care about it) and that this
  220. /// class is not instantiated so often (so the wasteful setting overhead
  221. /// should be marginal). On the other hand, doing it every time is
  222. /// beneficial if the application is threaded and different threads
  223. /// create different forwarder objects (and if signals work per thread).
  224. ///
  225. /// \exception SocketSessionError \c unix_file is invalid as a path name
  226. /// of a UNIX domain socket.
  227. /// \exception Unexpected Error in setting a filter for SIGPIPE (see above)
  228. /// \exception std::bad_alloc resource allocation failure
  229. ///
  230. /// \param unix_file Path name of the receiver.
  231. explicit SocketSessionForwarder(const std::string& unix_file);
  232. /// The destructor.
  233. ///
  234. /// If a connection has been established, it's automatically closed in
  235. /// the destructor.
  236. virtual ~SocketSessionForwarder();
  237. /// Establish a connection to the receiver.
  238. ///
  239. /// This method establishes a connection to the receiver at the path
  240. /// given on construction. It makes the underlying UNIX domain socket
  241. /// non blocking, so this method (or subsequent \c push() calls) does not
  242. /// block.
  243. ///
  244. /// \exception BadValue The method is called while an already
  245. /// established connection is still active.
  246. /// \exception SocketSessionError A system error in socket operation.
  247. virtual void connectToReceiver();
  248. /// Close the connection to the receiver.
  249. ///
  250. /// The connection must have been established by \c connectToReceiver().
  251. /// As long as it's met this method is exception free.
  252. ///
  253. /// \exception BadValue The connection hasn't been established.
  254. virtual void close();
  255. /// Forward a socket session to the receiver.
  256. ///
  257. /// This method takes a set of parameters that represent a single socket
  258. /// session, renders them in the "wire" format according to the internal
  259. /// protocol (see \ref SocketSessionUtility) and forwards them to
  260. /// the receiver through the UNIX domain connection.
  261. ///
  262. /// The connection must have been established by \c connectToReceiver().
  263. ///
  264. /// For simplicity and for the convenience of detecting application
  265. /// errors, this method imposes some restrictions on the parameters:
  266. /// - Socket family must be either \c AF_INET or \c AF_INET6
  267. /// - The address family (\c sa_family) member of the local and remote
  268. /// end points must be equal to the \c family parameter
  269. /// - Socket session data must not be empty (\c data_len must not be 0
  270. /// and \c data must not be NULL)
  271. /// - Data length must not exceed 65535
  272. /// These are not architectural limitation, and might be loosened in
  273. /// future versions as we see the need for flexibility.
  274. ///
  275. /// Since the underlying UNIX domain socket is non blocking
  276. /// (see the description for the constructor), a call to this method
  277. /// should either return immediately or result in exception (in case of
  278. /// "would block").
  279. ///
  280. /// \exception BadValue The method is called before establishing a
  281. /// connection or given parameters are invalid.
  282. /// \exception SocketSessionError A system error in socket operation,
  283. /// including the case where the write operation would block.
  284. ///
  285. /// \param sock The socket file descriptor
  286. /// \param family The address family (such as AF_INET6) of the socket
  287. /// \param type The socket type (such as SOCK_DGRAM) of the socket
  288. /// \param protocol The transport protocol (such as IPPROTO_UDP) of the
  289. /// socket
  290. /// \param local_end The local end point of the session in the form of
  291. /// \c sockaddr.
  292. /// \param remote_end The remote end point of the session in the form of
  293. /// \c sockaddr.
  294. /// \param data A pointer to the beginning of the memory region for the
  295. /// session data
  296. /// \param data_len The size of the session data in bytes.
  297. virtual void push(int sock, int family, int type, int protocol,
  298. const struct sockaddr& local_end,
  299. const struct sockaddr& remote_end,
  300. const void* data, size_t data_len);
  301. private:
  302. struct ForwarderImpl;
  303. ForwarderImpl* impl_;
  304. };
  305. /// Socket session object.
  306. ///
  307. /// The \c SocketSession class provides a convenient encapsulation
  308. /// for the notion of a socket session. It's instantiated with straightforward
  309. /// parameters corresponding to a socket session, and provides read only
  310. /// accessors to the parameters to ensure data integrity.
  311. ///
  312. /// In the initial design and implementation it's only used as a return type
  313. /// of \c SocketSessionReceiver::pop(), but it could also be used by
  314. /// the \c SocketSessionForwarder class or for other purposes.
  315. ///
  316. /// It is assumed that the original owner of a \c SocketSession object
  317. /// (e.g. a class or a function that constructs it) is responsible for validity
  318. /// of the data passed to the object. See the description of
  319. /// \c SocketSessionReceiver::pop() for the specific case of that usage.
  320. class SocketSession {
  321. public:
  322. /// The constructor.
  323. ///
  324. /// This is a trivial constructor, taking a straightforward representation
  325. /// of session parameters and storing them internally to ensure integrity.
  326. ///
  327. /// As long as the given parameters are valid it never throws an exception.
  328. ///
  329. /// \exception BadValue Given parameters don't meet the requirement
  330. /// (see the parameter descriptions).
  331. ///
  332. /// \param sock The socket file descriptor
  333. /// \param family The address family (such as AF_INET6) of the socket
  334. /// \param type The socket type (such as SOCK_DGRAM) of the socket
  335. /// \param protocol The transport protocol (such as IPPROTO_UDP) of the
  336. /// socket.
  337. /// \param local_end The local end point of the session in the form of
  338. /// \c sockaddr. Must not be NULL.
  339. /// \param remote_end The remote end point of the session in the form of
  340. /// \c sockaddr. Must not be NULL.
  341. /// \param data A pointer to the beginning of the memory region for the
  342. /// session data. Must not be NULL, and the subsequent \c data_len bytes
  343. /// must be valid.
  344. /// \param data_len The size of the session data in bytes. Must not be 0.
  345. SocketSession(int sock, int family, int type, int protocol,
  346. const sockaddr* local_end, const sockaddr* remote_end,
  347. const void* data, size_t data_len);
  348. /// Return the socket file descriptor.
  349. int getSocket() const { return (sock_); }
  350. /// Return the address family (such as AF_INET6) of the socket.
  351. int getFamily() const { return (family_); }
  352. /// Return the socket type (such as SOCK_DGRAM) of the socket.
  353. int getType() const { return (type_); }
  354. /// Return the transport protocol (such as IPPROTO_UDP) of the socket.
  355. int getProtocol() const { return (protocol_); }
  356. /// Return the local end point of the session in the form of \c sockaddr.
  357. const sockaddr& getLocalEndpoint() const { return (*local_end_); }
  358. /// Return the remote end point of the session in the form of \c sockaddr.
  359. const sockaddr& getRemoteEndpoint() const { return (*remote_end_); }
  360. /// Return a pointer to the beginning of the memory region for the session
  361. /// data.
  362. ///
  363. /// In the current implementation it should never be NULL, and the region
  364. /// of the size returned by \c getDataLength() is expected to be valid.
  365. const void* getData() const { return (data_); }
  366. /// Return the size of the session data in bytes.
  367. ///
  368. /// In the current implementation it should be always larger than 0.
  369. size_t getDataLength() const { return (data_len_); }
  370. private:
  371. const int sock_;
  372. const int family_;
  373. const int type_;
  374. const int protocol_;
  375. const sockaddr* local_end_;
  376. const sockaddr* remote_end_;
  377. const void* const data_;
  378. const size_t data_len_;
  379. };
  380. /// The receiver of socket sessions
  381. ///
  382. /// An object of this class holds a UNIX domain socket for an
  383. /// <em>established connection</em>, receives socket sessions from
  384. /// the remote forwarder, and provides the session to the application
  385. /// in the form of a \c SocketSession object.
  386. ///
  387. /// Note that this class is instantiated with an already connected socket;
  388. /// it's not a listening socket that is accepting connection requests from
  389. /// forwarders. It's application's responsibility to create the listening
  390. /// socket, listen on it and accept connections. Once the connection is
  391. /// established, the application would construct a \c SocketSessionReceiver
  392. /// object with the socket for the newly established connection.
  393. /// This behavior is based on the design decision that the application should
  394. /// decide when it performs (possibly) blocking operations (see \ref
  395. /// SocketSessionUtility for more details).
  396. ///
  397. /// See the description of \ref SocketSessionUtility for other details of how
  398. /// the session forwarding works.
  399. class SocketSessionReceiver : boost::noncopyable {
  400. public:
  401. /// The constructor.
  402. ///
  403. /// \exception SocketSessionError Any error on an operation that is
  404. /// performed on the given socket as part of initialization.
  405. /// \exception std::bad_alloc Resource allocation failure
  406. ///
  407. /// \param fd A UNIX domain socket for an established connection with
  408. /// a forwarder.
  409. explicit SocketSessionReceiver(int fd);
  410. /// The destructor.
  411. ///
  412. /// The destructor does \c not close the socket given on construction.
  413. /// It's up to the application what to do with it (note that the
  414. /// application would have to maintain the socket itself for detecting
  415. /// the existence of a new socket session asynchronously).
  416. ~SocketSessionReceiver();
  417. /// Receive a socket session from the forwarder.
  418. ///
  419. /// This method receives wire-format data (see \ref SocketSessionUtility)
  420. /// for a socket session on the UNIX domain socket, performs some
  421. /// validation on the data, and returns the session information in the
  422. /// form of a \c SocketSession object.
  423. ///
  424. /// The returned SocketSession object is valid only until the next time
  425. /// this method is called or until the \c SocketSessionReceiver object is
  426. /// destructed.
  427. ///
  428. /// The caller is responsible for closing the received socket (whose
  429. /// file descriptor is accessible via \c SocketSession::getSocket()).
  430. /// If the caller copies the returned \c SocketSession object, it's also
  431. /// responsible for making sure the descriptor is closed at most once.
  432. /// On the other hand, the caller is not responsible for freeing the
  433. /// socket session data (accessible via \c SocketSession::getData());
  434. /// the \c SocketSessionReceiver object will clean it up automatically.
  435. ///
  436. /// It ensures the following:
  437. /// - The address family is either \c AF_INET or \c AF_INET6
  438. /// - The address family (\c sa_family) member of the local and remote
  439. /// end points must be equal to the \c family parameter
  440. /// - The socket session data is not empty and does not exceed 65535
  441. /// bytes.
  442. /// If the validation fails or an unexpected system error happens
  443. /// (including a connection close in the meddle of reception), it throws
  444. /// an SocketSessionError exception. When this happens, it's very
  445. /// unlikely that a subsequent call to this method succeeds, so in reality
  446. /// the application is expected to destruct it and close the socket in
  447. /// such a case.
  448. ///
  449. /// \exception SocketSessionError Invalid data is received or a system
  450. /// error on socket operation happens.
  451. /// \exception std::bad_alloc Resource allocation failure
  452. ///
  453. /// \return A \c SocketSession object corresponding to the extracted
  454. /// socket session.
  455. SocketSession pop();
  456. private:
  457. struct ReceiverImpl;
  458. ReceiverImpl* impl_;
  459. };
  460. }
  461. }
  462. }
  463. #endif // __SOCKETSESSION_H_
  464. // Local Variables:
  465. // mode: c++
  466. // End: