Factor out some Dinit client functions tp a new header (dinit-client.h).
[oweals/dinit.git] / src / includes / dinit-client.h
1 #include <cstdint>
2
3 // Client library for Dinit clients
4
5
6 using handle_t = uint32_t;
7
8 class read_cp_exception
9 {
10     public:
11     int errcode;
12     read_cp_exception(int err) : errcode(err) { }
13 };
14
15 // Fill a circular buffer from a file descriptor, until it contains at least _rlength_ bytes.
16 // Throws read_cp_exception if the requested number of bytes cannot be read, with:
17 //     errcode = 0   if end of stream (remote end closed)
18 //     errcode = errno   if another error occurred
19 // Note that EINTR is ignored (i.e. the read will be re-tried).
20 inline void fill_buffer_to(cpbuffer<1024> *buf, int fd, int rlength)
21 {
22     do {
23         int r = buf->fill_to(fd, rlength);
24         if (r == -1) {
25             if (errno != EINTR) {
26                 throw read_cp_exception(errno);
27             }
28         }
29         else if (r == 0) {
30             throw read_cp_exception(0);
31         }
32         else {
33             return;
34         }
35     }
36     while (true);
37 }
38
39 // Wait for a reply packet, skipping over any information packets that are received in the meantime.
40 inline void wait_for_reply(cpbuffer<1024> &rbuffer, int fd)
41 {
42     fill_buffer_to(&rbuffer, fd, 1);
43
44     while (rbuffer[0] >= 100) {
45         // Information packet; discard.
46         fill_buffer_to(&rbuffer, fd, 2);
47         int pktlen = (unsigned char) rbuffer[1];
48
49         rbuffer.consume(1);  // Consume one byte so we'll read one byte of the next packet
50         fill_buffer_to(&rbuffer, fd, pktlen);
51         rbuffer.consume(pktlen - 1);
52     }
53 }
54
55 // Wait for an info packet. If any other reply packet comes, throw a read_cp_exception.
56 inline void wait_for_info(cpbuffer<1024> &rbuffer, int fd)
57 {
58     fill_buffer_to(&rbuffer, fd, 2);
59
60     if (rbuffer[0] < 100) {
61         throw read_cp_exception(0);
62     }
63
64     int pktlen = (unsigned char) rbuffer[1];
65     fill_buffer_to(&rbuffer, fd, pktlen);
66 }
67
68 // Write *all* the requested buffer and re-try if necessary until
69 // the buffer is written or an unrecoverable error occurs.
70 inline int write_all(int fd, const void *buf, size_t count)
71 {
72     const char *cbuf = static_cast<const char *>(buf);
73     int w = 0;
74     while (count > 0) {
75         int r = write(fd, cbuf, count);
76         if (r == -1) {
77             if (errno == EINTR) continue;
78             return r;
79         }
80         w += r;
81         cbuf += r;
82         count -= r;
83     }
84     return w;
85 }