PageRenderTime 52ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/include/socket.hh

https://bitbucket.org/modelnine/protoproxy
C++ Header | 449 lines | 75 code | 56 blank | 318 comment | 4 complexity | 9a1f5c7a9289eee8f76041eaf1cdeea5 MD5 | raw file
  1. /*
  2. * socket.hh
  3. *
  4. * Copyright (c) 2012, Heiko Wundram.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * * Neither the name of modelnine.org, protoproxy nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL HEIKO WUNDRAM BE LIABLE FOR ANY
  23. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. * Created on: 31.01.2012
  31. * Author: Heiko Wundram <modelnine@modelnine.org>
  32. */
  33. #ifndef SOCKET_HH_
  34. #define SOCKET_HH_
  35. #include <sys/socket.h>
  36. #include <sys/types.h>
  37. #include <cstdarg>
  38. #include <cstddef>
  39. #include <poll.h>
  40. #include "logger.hh"
  41. #include "types.hh"
  42. namespace protoproxy {
  43. /**
  44. * Abstract base class representing a socket (file descriptor) and its
  45. * attached callbacks. This class implements no own functionality, but rather
  46. * requires derived classes to implement actual callbacks/functions on the
  47. * socket.
  48. */
  49. class socket :
  50. protected logger {
  51. /**
  52. * Reactor manages our internal state, and as such requires access to
  53. * internal data elements of the socket.
  54. */
  55. friend class reactor;
  56. /**
  57. * Proxy socket as a specialized subclass of socket may access internal
  58. * fields of the socket directly.
  59. */
  60. friend class proxy_socket;
  61. private:
  62. /**
  63. * Hidden methods.
  64. */
  65. socket(const socket& other);
  66. socket& operator =(const socket& other);
  67. /**
  68. * Boolean indicating whether this socket wants to be destroyed by the
  69. * reactor when it's attached to it and the reactor cleans up.
  70. */
  71. const bool m_destroy;
  72. /**
  73. * Reactor this socket is bound to. In case there is no reactor currently
  74. * bound which manages callbacks on the socket, this is NULL.
  75. */
  76. reactor* m_reactor;
  77. /**
  78. * Previous socket in reactor chain. Pointer is only valid when a reactor
  79. * is currently setup.
  80. */
  81. socket* m_prev;
  82. /**
  83. * Next socket in reactor chain. Pointer is only valid when a reactor is
  84. * currently set up.
  85. */
  86. socket* m_next;
  87. /**
  88. * File descriptor bound to this socket. In case the file descriptor is
  89. * unbound, this is -1, in case a file descriptor is bound and a reactor
  90. * is set up, this is an index into the reactors m_pollfds array, otherwise
  91. * it is the plain file descriptor of the socket.
  92. */
  93. int m_fd;
  94. /**
  95. * Local event mask for the socket, managed by the socket when it's bound
  96. * and unbound from a reactor. When the socket is bound, this mask gets
  97. * transferred to the reactor poll descriptor and remains in sync with
  98. * it.
  99. */
  100. short m_events;
  101. /**
  102. * Identifier used to identify the next timeout. This is a large integer
  103. * type which makes it improbable that timeout IDs will begin overlapping.
  104. */
  105. std::size_t m_nexttimeoutid;
  106. /**
  107. * Timeouts currently attached to this socket, as a time measured against
  108. * CLOCK_REALTIME. This is a singly linked list of socket timeouts,
  109. * ordered in ascending timeout and time of insertion. When there are no
  110. * timeouts pending, this is NULL.
  111. */
  112. socket_timeout* m_nexttimeout;
  113. /**
  114. * Pointer to m_next in the last timeout instance registered in the
  115. * timeout singly linked list starting with m_nexttimeout. This field is
  116. * only valid when timeouts are set up with m_nexttimeout.
  117. */
  118. socket_timeout** m_lasttimeout;
  119. /**
  120. * Handle attachment of this socket to a reactor. This callback is called
  121. * when the attachment process has been completed successfully. The default
  122. * implementation does nothing.
  123. */
  124. virtual void handle_attach();
  125. /**
  126. * Handle errors occuring on this socket. The default implementation of
  127. * this method removes the socket from the reactor and destroys it in
  128. * case the socket is destructible, otherwise it just detaches the
  129. * socket from the reactor. Error cannot be controlled, and will always
  130. * be delivered by the reactor.
  131. */
  132. virtual void handle_error();
  133. /**
  134. * Handle reads on this socket. The default implementation of this method
  135. * throws an exception. This is only delivered in case the event mask
  136. * requests to be informed of read events (want_read()).
  137. */
  138. virtual void handle_read();
  139. #if POLLRDBAND != POLLPRI
  140. /**
  141. * Handle priority reads on this socket. The default implementation of this
  142. * method throws an exception. This is only delivered in case the event
  143. * mask requests to be informed of priority read events
  144. * (want_priority_read()).
  145. */
  146. virtual void handle_priority_read();
  147. #endif
  148. /**
  149. * Handle high priority reads on this socket. The default implementation of
  150. * this method throws an exception. This is only delivered in case the
  151. * event mask requests to be informed of high priority read events
  152. * (want_high_priority_read()).
  153. */
  154. virtual void handle_high_priority_read();
  155. /**
  156. * Handle writes on this socket. The default implementation of this method
  157. * throws an exception. This is only delivered in case the event mask
  158. * requests to be informed of write events (want_write()).
  159. */
  160. virtual void handle_write();
  161. #if POLLWRBAND != POLLWRNORM
  162. /**
  163. * Handle priority writes on this socket. The default implementation of
  164. * this method throws an exception. This is only delivered in case the
  165. * event mask requests to be informed of priority write events
  166. * (want_priority_write()).
  167. */
  168. virtual void handle_priority_write();
  169. #endif
  170. /**
  171. * Handle hangup on this socket. The default implementation does nothing.
  172. * Hangup cannot be controlled, and will always be delivered when
  173. * signalled by the reactor.
  174. */
  175. virtual void handle_hangup();
  176. /**
  177. * Handle timeout signalled by the internal timeout parameter, processing
  178. * the socket. The default implementation of this method throws an
  179. * exception. The identifier passed as ID is the identifier that was
  180. * granted on timeout registration.
  181. * @param id Identifier of the timeout that's expired.
  182. */
  183. virtual void handle_timeout(std::size_t id);
  184. /**
  185. * Handle detachment of the socket from a reactor. The callback is called
  186. * when the detachment process has completed. The default implementation
  187. * does nothing. This callback is not called when the socket is detached
  188. * from the reactor in its destructor, or the socket is being destroyed
  189. * with a reactor still bound.
  190. */
  191. virtual void handle_detach();
  192. /**
  193. * Implementation of logging target for sockets. This dispatches the log
  194. * message to the reactor this socket is currently bound to (in case a
  195. * reactor is set up), otherwise it handles the message through a generic
  196. * logging channel.
  197. * @param level Level of message to log.
  198. * @param domain Domain of the log message.
  199. * @param msg Message to log.
  200. * @param args Arguments passed to message as a varargs set.
  201. */
  202. virtual void log(loglevel level, logdomain domain, const char* msg,
  203. va_list args) __attribute__((format(printf, 4, 0)));
  204. protected:
  205. /**
  206. * Initialize a new socket which is not bound to a reactor and has no
  207. * file descriptor bound to it. In case this socket is designed to be
  208. * used as a stack variable, pass destroy as false.
  209. * @param destroy Boolean indicating destruction by reactor.
  210. * @param defdomain Default domain of log messages for socket.
  211. */
  212. explicit socket(bool destroy = true, logdomain defdomain = SOCKET);
  213. /**
  214. * Create a new socket of the specified domain, type and protocol, which is
  215. * not bound to a reactor. In case this socket is designed to be used as
  216. * a stack variable, pass destroy as false.
  217. * @param domain Domain of socket to create.
  218. * @param type Type of socket to create.
  219. * @param protocol Protocol of socket to create.
  220. * @param destroy Boolean indicating destruction by reactor.
  221. * @param defdomain Default domain of log messages for socket.
  222. */
  223. socket(int domain, int type, int protocol = 0, bool destroy = true,
  224. logdomain defdomain = SOCKET);
  225. /**
  226. * Create a new socket bound to the passed open file descriptor (which must
  227. * be an integer), setting it up as appropriate. In case this socket is
  228. * designed to be used as a stack variable, pass destroy as false.
  229. * @param fd File descriptor to bind socket to.
  230. * @param defdomain Default domain of log messages for socket.
  231. */
  232. explicit socket(int fd, bool destroy = true, logdomain defdomain = SOCKET);
  233. /**
  234. * Fetch the reactor that is attached to this socket, returning a reference
  235. * to it.
  236. * @return Reference to bound reactor.
  237. */
  238. reactor& reactor_() const;
  239. /**
  240. * Set the relevant flags in the current event mask for this socket to
  241. * enable reads. It is an error to set flags on socket when it is not
  242. * opened.
  243. * @param read Whether to set or clear the read flag.
  244. */
  245. void want_read(bool read = true);
  246. #if POLLRDBAND != POLLPRI
  247. /**
  248. * Set the relevant flags in the current event mask for this socket to
  249. * enable priority reads. It is an error to set flags on socket when it is
  250. * not opened.
  251. * @param read Whether to set or clear the priority read flag.
  252. */
  253. void want_priority_read(bool read = true);
  254. #endif
  255. /**
  256. * Set the relevant flags in the current event mask for this socket to
  257. * enable high priority reads. It is an error to set flags on socket when
  258. * it is not opened.
  259. * @param read Whether to set or clear the high priority read flag.
  260. */
  261. void want_high_priority_read(bool read = true);
  262. /**
  263. * Set the relevant flags in the current event mask for this socket to
  264. * enable writes. It is an error to set flags on socket when
  265. * it is not opened.
  266. * @param write Whether to set or clear the write flag.
  267. */
  268. void want_write(bool write = true);
  269. #if POLLWRBAND != POLLWRNORM
  270. /**
  271. * Set the relevant flags in the current event mask for this socket to
  272. * enable priority writes. It is an error to set flags on socket when
  273. * it is not opened.
  274. * @param write Whether to set or clear the priority write flag.
  275. */
  276. void want_priority_write(bool write = true);
  277. #endif
  278. /**
  279. * Add a new timeout in the specified number of milli-seconds, to dispatch
  280. * on this socket. The return value indicates the timeout ID of the newly
  281. * attached timeout. Be aware that timeouts will only be triggered when the
  282. * socket is actually bound to a reactor. When passing zero or negative
  283. * timeouts, the timeout expires immediately when the reactor loop next
  284. * dispatches timeouts to this socket.
  285. * @param msecs Milli-seconds after which the timeout expires.
  286. * @return Identifier which represents this timeout instance.
  287. */
  288. std::size_t addtimeout(int msecs);
  289. /**
  290. * Cancel the timeout specified by the passed timeout ID. In case the
  291. * timeout has already expired, this method throws an exception. As
  292. * canceling a timeout needs to walk the entire tree, this is an expensive
  293. * operation.
  294. * @param timeoutid Timeout identifier to cancel.
  295. */
  296. void canceltimeout(std::size_t timeoutid);
  297. /**
  298. * Create a new socket of the specified domain, type and protocol. This
  299. * simply dispatches to the underlying operating system callbacks to create
  300. * the file descriptor. It is only valid to call create when the socket is
  301. * not created (open()) yet.
  302. * @param domain Domain of socket to create.
  303. * @param type Type of socket to create.
  304. * @param protocol Protocol of socket to create.
  305. */
  306. void create(int domain, int type, int protocol = 0);
  307. /**
  308. * Set specified socket option to the passed integer value, calling to
  309. * the base option setter.
  310. * @param level Level of socket option.
  311. * @param optname Option name.
  312. * @param val Value to set up.
  313. */
  314. void setsockopt(int level, int optname, const int& val);
  315. /**
  316. * Bind the current socket to the passed address, setting up the binding
  317. * as specified. It is only valid to bind a socket when the socket has
  318. * been created.
  319. * @param addr Address to bind to.
  320. * @param addrlen Length of address in address structure.
  321. */
  322. void bind(const sockaddr& addr, socklen_t addrlen);
  323. /**
  324. * Start listening on the current socket, with the specified backlog. It
  325. * is only valid to listen on a socket in case it has been created.
  326. * @param backlog Backlog to start listening with.
  327. */
  328. void listen(int backlog);
  329. /**
  330. * Accept an incoming connection on the currently open socket, returning
  331. * the file descriptor of the accepted connection as integer. The address
  332. * of the incoming connection is set up in the passed reference parameters.
  333. * @param addr Address of incoming connection.
  334. * @param addrlen Length of address.
  335. * @return File descriptor accepted on socket.
  336. */
  337. int accept(sockaddr& addr, socklen_t& addrlen);
  338. /**
  339. * Receive data from socket, returning the length of data actually received
  340. * on input. The actual length received is returned as argument. When data
  341. * can't be received because the operation would block, returns zero, if
  342. * the remote end disconnected the receiving channel, returns -1. All other
  343. * errors cause an exception.
  344. * @param buf Buffer to receive to.
  345. * @param len Length of space available in buffer.
  346. * @return Actual size read.
  347. */
  348. ssize_t read(void* buf, std::size_t len);
  349. /**
  350. * Write out the specified set of data to the socket, returning the actual
  351. * amount of length able to be written. In case no more data can be written
  352. * because the remote end has closed the channel, returns -1.
  353. * @param buf Buffer to send from.
  354. * @param len Length of data in buffer to send.
  355. * @return Actual size sent.
  356. */
  357. ssize_t write(const void* buf, std::size_t len);
  358. /**
  359. * Close the current socket, releasing any bound file descriptor and
  360. * resetting any remaining internal state for the socket. In case the
  361. * socket is currently not open, this raises an exception.
  362. */
  363. void close();
  364. public:
  365. /**
  366. * Clean up the socket, destroying any remaining internal state of the
  367. * socket in the process. This detaches the socket from a reactor in case
  368. * it is still bound to one, but will not call handle_detach() on the
  369. * socket to signal the detachment.
  370. */
  371. virtual ~socket();
  372. /**
  373. * Check whether socket is opened, returning a boolean indicating that a
  374. * descriptor is bound.
  375. * @return Flag indicating that the descriptor is bound.
  376. */
  377. bool open() const;
  378. /**
  379. * Check whether socket is currently in attached state, returning an
  380. * appropriate boolean.
  381. * @return Boolean indicating whether socket is attached.
  382. */
  383. bool attached() const;
  384. /**
  385. * Detach the current socket from a possibly attached reactor, clearing
  386. * out any remaining reactor bindings. This method gives strong exception
  387. * safety in that the reactor and socket state are unchanged in case it
  388. * fails, and the socket is completely detached in case it succeeds.
  389. */
  390. void detach();
  391. };
  392. }
  393. #endif /* SOCKET_HH_ */