control.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #ifndef DINIT_CONTROL_H
  2. #define DINIT_CONTROL_H
  3. #include <list>
  4. #include <vector>
  5. #include <unordered_map>
  6. #include <map>
  7. #include <limits>
  8. #include <cstddef>
  9. #include <unistd.h>
  10. #include "dinit.h"
  11. #include "dinit-log.h"
  12. #include "control-cmds.h"
  13. #include "service-listener.h"
  14. #include "cpbuffer.h"
  15. // Control connection for dinit
  16. class control_conn_t;
  17. class control_conn_watcher;
  18. // forward-declaration of callback:
  19. inline dasynq::rearm control_conn_cb(eventloop_t *loop, control_conn_watcher *watcher, int revents);
  20. // Pointer to the control connection that is listening for rollback completion
  21. extern control_conn_t * rollback_handler_conn;
  22. extern int active_control_conns;
  23. // "packet" format:
  24. // (1 byte) packet type
  25. // (N bytes) additional data (service name, etc)
  26. // for LOADSERVICE/FINDSERVICE:
  27. // (2 bytes) service name length
  28. // (M bytes) service name (without nul terminator)
  29. // Information packet:
  30. // (1 byte) packet type, >= 100
  31. // (1 byte) packet length (including all fields)
  32. // N bytes: packet data (N = (length - 2))
  33. class service_set;
  34. class service_record;
  35. class control_conn_watcher : public eventloop_t::bidi_fd_watcher_impl<control_conn_watcher>
  36. {
  37. inline rearm receive_event(eventloop_t &loop, int fd, int flags) noexcept
  38. {
  39. return control_conn_cb(&loop, this, flags);
  40. }
  41. eventloop_t * event_loop;
  42. public:
  43. control_conn_watcher(eventloop_t & event_loop_p) : event_loop(&event_loop_p)
  44. {
  45. // constructor
  46. }
  47. control_conn_watcher(const control_conn_watcher &) = delete;
  48. void operator=(const control_conn_watcher &) = delete;
  49. rearm read_ready(eventloop_t &loop, int fd) noexcept
  50. {
  51. return receive_event(loop, fd, dasynq::IN_EVENTS);
  52. }
  53. rearm write_ready(eventloop_t &loop, int fd) noexcept
  54. {
  55. return receive_event(loop, fd, dasynq::OUT_EVENTS);
  56. }
  57. void set_watches(int flags)
  58. {
  59. eventloop_t::bidi_fd_watcher::set_watches(*event_loop, flags);
  60. }
  61. };
  62. class control_conn_t : private service_listener
  63. {
  64. friend rearm control_conn_cb(eventloop_t *loop, control_conn_watcher *watcher, int revents);
  65. public:
  66. // A mapping between service records and their associated numerical identifier used
  67. // in communction
  68. using handle_t = uint32_t;
  69. private:
  70. control_conn_watcher iob;
  71. eventloop_t &loop;
  72. service_set *services;
  73. bool bad_conn_close = false; // close when finished output?
  74. bool oom_close = false; // send final 'out of memory' indicator
  75. // The packet length before we need to re-check if the packet is complete.
  76. // process_packet() will not be called until the packet reaches this size.
  77. int chklen;
  78. // Receive buffer
  79. cpbuffer<1024> rbuf;
  80. template <typename T> using list = std::list<T>;
  81. template <typename T> using vector = std::vector<T>;
  82. std::unordered_multimap<service_record *, handle_t> service_key_map;
  83. std::map<handle_t, service_record *> key_service_map;
  84. // Buffer for outgoing packets. Each outgoing back is represented as a vector<char>.
  85. list<vector<char>> outbuf;
  86. // Current index within the first outgoing packet (all previous bytes have been sent).
  87. unsigned outpkt_index = 0;
  88. // Queue a packet to be sent
  89. // Returns: false if the packet could not be queued and a suitable error packet
  90. // could not be sent/queued (the connection should be closed);
  91. // true (with bad_conn_close == false) if the packet was successfully
  92. // queued;
  93. // true (with bad_conn_close == true) if the packet was not successfully
  94. // queued (but a suitable error packate has been queued).
  95. // The in/out watch enabled state will also be set appropriately.
  96. bool queue_packet(vector<char> &&v) noexcept;
  97. bool queue_packet(const char *pkt, unsigned size) noexcept;
  98. // Process a packet.
  99. // Returns: true (with bad_conn_close == false) if successful
  100. // true (with bad_conn_close == true) if an error packet was queued
  101. // false if an error occurred but no error packet could be queued
  102. // (connection should be closed).
  103. // Throws:
  104. // std::bad_alloc - if an out-of-memory condition prevents processing
  105. bool process_packet();
  106. // Process a STARTSERVICE/STOPSERVICE packet. May throw std::bad_alloc.
  107. bool process_start_stop(int pktType);
  108. // Process a FINDSERVICE/LOADSERVICE packet. May throw std::bad_alloc.
  109. bool process_find_load(int pktType);
  110. // Process an UNPINSERVICE packet. May throw std::bad_alloc.
  111. bool process_unpin_service();
  112. // Process an UNLOADSERVICE packet.
  113. bool process_unload_service();
  114. // List all loaded services and their state.
  115. bool list_services();
  116. // Add a dependency between two services.
  117. bool add_service_dep(bool do_start = false);
  118. // Remove a dependency between two services.
  119. bool rm_service_dep();
  120. // Query service path / load mechanism.
  121. bool query_load_mech();
  122. // Notify that data is ready to be read from the socket. Returns true if the connection should
  123. // be closed.
  124. bool data_ready() noexcept;
  125. bool send_data() noexcept;
  126. // Allocate a new handle for a service; may throw std::bad_alloc
  127. handle_t allocate_service_handle(service_record *record);
  128. // Find the service corresponding to a service handle; returns nullptr if not found.
  129. service_record *find_service_for_key(handle_t key) noexcept
  130. {
  131. try {
  132. return key_service_map.at(key);
  133. }
  134. catch (std::out_of_range &exc) {
  135. return nullptr;
  136. }
  137. }
  138. // Close connection due to out-of-memory condition.
  139. void do_oom_close() noexcept
  140. {
  141. bad_conn_close = true;
  142. oom_close = true;
  143. iob.set_watches(dasynq::OUT_EVENTS);
  144. }
  145. // Process service event broadcast.
  146. // Note that this can potentially be called during packet processing (upon issuing
  147. // service start/stop orders etc).
  148. void service_event(service_record * service, service_event_t event) noexcept final override
  149. {
  150. // For each service handle corresponding to the event, send an information packet.
  151. auto range = service_key_map.equal_range(service);
  152. auto & i = range.first;
  153. auto & end = range.second;
  154. try {
  155. while (i != end) {
  156. uint32_t key = i->second;
  157. std::vector<char> pkt;
  158. constexpr int pktsize = 3 + sizeof(key);
  159. pkt.reserve(pktsize);
  160. pkt.push_back(DINIT_IP_SERVICEEVENT);
  161. pkt.push_back(pktsize);
  162. char * p = (char *) &key;
  163. for (int j = 0; j < (int)sizeof(key); j++) {
  164. pkt.push_back(*p++);
  165. }
  166. pkt.push_back(static_cast<char>(event));
  167. queue_packet(std::move(pkt));
  168. ++i;
  169. }
  170. }
  171. catch (std::bad_alloc &exc) {
  172. do_oom_close();
  173. }
  174. }
  175. public:
  176. control_conn_t(eventloop_t &loop, service_set * services_p, int fd)
  177. : iob(loop), loop(loop), services(services_p), chklen(0)
  178. {
  179. iob.add_watch(loop, fd, dasynq::IN_EVENTS);
  180. active_control_conns++;
  181. }
  182. control_conn_t(const control_conn_t &) = delete;
  183. bool rollback_complete() noexcept;
  184. virtual ~control_conn_t() noexcept;
  185. };
  186. inline dasynq::rearm control_conn_cb(eventloop_t * loop, control_conn_watcher * watcher, int revents)
  187. {
  188. // Get the address of the containing control_connt_t object:
  189. _Pragma ("GCC diagnostic push")
  190. _Pragma ("GCC diagnostic ignored \"-Winvalid-offsetof\"")
  191. uintptr_t cc_addr = reinterpret_cast<uintptr_t>(watcher) - offsetof(control_conn_t, iob);
  192. control_conn_t *conn = reinterpret_cast<control_conn_t *>(cc_addr);
  193. _Pragma ("GCC diagnostic pop")
  194. if (revents & dasynq::IN_EVENTS) {
  195. if (conn->data_ready()) {
  196. delete conn;
  197. return dasynq::rearm::REMOVED;
  198. }
  199. }
  200. if (revents & dasynq::OUT_EVENTS) {
  201. if (conn->send_data()) {
  202. delete conn;
  203. return dasynq::rearm::REMOVED;
  204. }
  205. }
  206. return dasynq::rearm::NOOP;
  207. }
  208. #endif