Minor re-arrangement of fields and code documentation improvements.
[oweals/dinit.git] / control.h
1 #ifndef DINIT_CONTROL_H
2 #define DINIT_CONTROL_H
3
4 #include <list>
5 #include <vector>
6
7 #include <unistd.h>
8 #include <ev++.h>
9 #include "dinit-log.h"
10 #include "control-cmds.h"
11
12 // Control connection for dinit
13
14 // TODO: Use the input buffer as a circular buffer, instead of chomping data from
15 // the front using a data move.
16
17 // forward-declaration of callback:
18 static void control_conn_cb(struct ev_loop * loop, ev_io * w, int revents);
19
20 class ControlConn;
21
22 // Pointer to the control connection that is listening for rollback completion
23 extern ControlConn * rollback_handler_conn;
24
25 extern int active_control_conns;
26
27 // "packet" format:
28 // (1 byte) packet type
29 // (N bytes) additional data (service name, etc)
30 //   for STARTSERVICE/STOPSERVICE:
31 //      (2 bytes) service name length
32 //      (M buyes) service name (without nul terminator)
33
34 class ServiceSet;
35
36
37 class ControlConn
38 {
39     friend void control_conn_cb(struct ev_loop *, ev_io *, int);
40     
41     struct ev_io iob;
42     struct ev_loop *loop;
43     ServiceSet *service_set;
44     
45     bool bad_conn_close; // close when finished output?
46     bool oom_close;      // send final 'out of memory' indicator
47
48     // The packet length before we need to re-check if the packet is complete.
49     // processPacket() will not be called until the packet reaches this size.
50     int chklen;
51     
52     char * iobuf;
53     int bufidx;
54     
55     template <typename T> using list = std::list<T>;
56     template <typename T> using vector = std::vector<T>;
57     
58     // Buffer for outgoing packets. Each outgoing back is represented as a vector<char>.
59     list<vector<char>> outbuf;
60     // Current index within the first outgoing packet (all previous bytes have been sent).
61     unsigned outpkt_index = 0;
62     
63     // Queue a packet to be sent
64     //  Returns:  true if the packet was successfully queued, false if otherwise
65     //            (eg if out of memory); in the latter case the connection might
66     //            no longer be valid (iff there are no outgoing packets queued).
67     bool queuePacket(vector<char> &&v) noexcept;
68     bool queuePacket(const char *pkt, unsigned size) noexcept;
69
70     // Process a packet. Can cause the ControlConn to be deleted iff there are no
71     // outgoing packets queued.
72     void processPacket();
73
74     // Notify that data is ready to be read from the socket. Returns true in cases where the
75     // connection was deleted with potentially pending outgoing packets.
76     bool dataReady() noexcept;
77     
78     void sendData() noexcept;
79     
80     public:
81     ControlConn(struct ev_loop * loop, ServiceSet * service_set, int fd) : loop(loop), service_set(service_set), bufidx(0), chklen(0)
82     {
83         iobuf = new char[1024];
84     
85         ev_io_init(&iob, control_conn_cb, fd, EV_READ);
86         iob.data = this;
87         ev_io_start(loop, &iob);
88         
89         active_control_conns++;
90     }
91     
92     bool rollbackComplete() noexcept;
93         
94     ~ControlConn() noexcept;
95 };
96
97
98 static void control_conn_cb(struct ev_loop * loop, ev_io * w, int revents)
99 {
100     ControlConn *conn = (ControlConn *) w->data;
101     if (revents & EV_READ) {
102         if (conn->dataReady()) {
103             // ControlConn was deleted
104             return;
105         }
106     }
107     if (revents & EV_WRITE) {
108         conn->sendData();
109     }    
110 }
111
112 #endif