Various control protocol improvements, still needs significant work.
[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
15 // forward-declaration of callback:
16 static void control_conn_cb(struct ev_loop * loop, ev_io * w, int revents);
17
18 class ControlConn;
19
20 // Pointer to the control connection that is listening for rollback completion
21 extern ControlConn * rollback_handler_conn;
22
23 extern int active_control_conns;
24
25 // "packet" format:
26 // (1 byte) packet type
27 // (N bytes) additional data (service name, etc)
28 //   for STARTSERVICE/STOPSERVICE:
29 //      (2 bytes) service name length
30 //      (M buyes) service name (without nul terminator)
31
32 class ServiceSet;
33
34
35 class ControlConn
36 {
37     struct ev_io iob;
38     struct ev_loop *loop;
39     ServiceSet *service_set;
40     char * iobuf;
41     int bufidx;
42     
43     bool bad_conn_close; // close when finished output?
44     //bool bad_conn_wrerr; // write error has occurred
45     bool oom_close;      // send final 'out of memory' indicator
46     
47     template <typename T> using list = std::list<T>;
48     template <typename T> using vector = std::vector<T>;
49     
50     // Buffer for outgoing packets. Each outgoing back is represented as a vector<char>.
51     list<vector<char>> outbuf;
52     unsigned outpkt_index = 0;
53     
54     // The packet length before we need to re-check if the packet is complete
55     int chklen;
56     
57     // Queue a packet to be sent
58     //  Returns:  true if the packet was successfully queued, false if otherwise
59     //            (eg if out of memory); in the latter case the connection might
60     //            no longer be valid (iff there are no outgoing packets queued).
61     bool queuePacket(vector<char> &&v) noexcept;
62     bool queuePacket(const char *pkt, unsigned size) noexcept;
63
64     // Process a packet. Can cause the ControlConn to be deleted iff there are no
65     // outgoing packets queued.
66     void processPacket();
67     
68     public:
69     ControlConn(struct ev_loop * loop, ServiceSet * service_set, int fd) : loop(loop), service_set(service_set), bufidx(0), chklen(0)
70     {
71         iobuf = new char[1024];
72     
73         ev_io_init(&iob, control_conn_cb, fd, EV_READ);
74         iob.data = this;
75         ev_io_start(loop, &iob);
76         
77         active_control_conns++;
78     }
79     
80     void rollbackComplete() noexcept;
81     // Notify that data is ready to be read from the socket.
82     void dataReady() noexcept;
83     void sendData() noexcept;
84     
85     
86     ~ControlConn() noexcept;
87 };
88
89
90 static void control_conn_cb(struct ev_loop * loop, ev_io * w, int revents)
91 {
92     ControlConn *conn = (ControlConn *) w->data;
93     if (revents & EV_READ) {
94         conn->dataReady();
95     }
96     // TODO issue here: what if above deletes the connection?
97     if (revents & EV_WRITE) {
98         conn->sendData();
99     }    
100 }
101
102 #endif