forked from uwcms/sysmgr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmgmt_protocol.h
287 lines (231 loc) · 7.79 KB
/
mgmt_protocol.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#ifndef _MGMT_PROTOCOL_H
#define _MGMT_PROTOCOL_H
#define PROTOCOL_MAX_LINE_LENGTH 256
#define PROTOCOL_MAX_WRITEBUF (1024*1024)
#define PROTOCOL_MAX_UNAUTH_BYTES (PROTOCOL_MAX_LINE_LENGTH*5)
#include <errno.h>
#include "sysmgr.h"
#include "scope_lock.h"
#include <limits.h>
DEFINE_EXCEPTION(Protocol_Exception, Sysmgr_Exception);
class Client;
enum AuthLevel {
AUTH_NONE = 0,
AUTH_READ = 1,
AUTH_MANAGE = 2,
AUTH_RAW = 3
};
class EventFilter {
public:
uint8_t crate;
uint8_t fru;
std::string card;
std::string sensor;
uint16_t assertmask;
uint16_t deassertmask;
EventFilter() : crate(0xff), fru(0xff), card(""), sensor(""), assertmask(0x7fff), deassertmask(0x7fff) { };
EventFilter(uint8_t crate, uint8_t fru, std::string card, std::string sensor, uint16_t assertmask, uint16_t deassertmask)
: crate(crate), fru(fru), card(card), sensor(sensor), assertmask(assertmask & 0x7fff), deassertmask(deassertmask & 0x7fff) { };
bool match(EventData event) {
if (crate != 0xff && crate != event.crate) return false;
if (fru != 0xff && fru != event.fru) return false;
if (card != "" && card != event.card) return false;
if (sensor != "" && sensor != event.sensor) return false;
if (event.assertion)
return (assertmask & (1 << event.offset));
else
return (deassertmask & (1 << event.offset));
}
};
class Command {
protected:
pthread_mutex_t lock;
bool reapable;
uint32_t msgid;
const std::string rawcmd;
const std::vector<std::string> cmd;
std::string writebuf;
public:
DEFINE_EXCEPTION(ProtocolParseException, Protocol_Exception);
static std::vector<std::string> tokenize(std::string line) {
std::vector<std::string> tokens;
bool inquote = false;
bool newtoken = true;
for (unsigned int i = 0; i < line.size(); i++) {
char c = line[i];
bool consume = false;
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
if (!inquote) {
newtoken = true;
consume = true;
}
}
if (c == '"') {
if (newtoken) {
newtoken = false;
tokens.push_back(std::string());
}
inquote = !inquote;
if (inquote && i != 0 && line[i-1] == '"') {
// Append escaped " character.
}
else {
consume = true;
}
}
if (!consume) {
if (newtoken) {
newtoken = false;
tokens.push_back(std::string());
}
tokens.back().push_back(line[i]);
}
/*
dmprintf("\nc:'%c', q:%u, n:%u, x:%u, t%u:'%s\"\n",
c,
(inquote ? 1 : 0),
(newtoken ? 1 : 0),
(consume ? 1 : 0),
tokens.size(),
tokens.back().c_str());
*/
}
if (inquote)
THROWMSG(ProtocolParseException, "Unterminated Quoted String");
return tokens;
}
DEFINE_EXCEPTION(InvalidIntegerException, ProtocolParseException);
static uint32_t parse_uint32(std::string token) {
const char *str = token.c_str();
char *end;
unsigned long int val = strtoul(str, &end, 0);
if (end == str || *end != '\0')
THROWMSG(InvalidIntegerException, "Integer parsing failed: Invalid string");
if ((val == ULONG_MAX && errno == ERANGE) || val > 0xffffffffu)
THROWMSG(InvalidIntegerException, "Integer parsing failed: Overflow");
return val;
}
static uint8_t parse_uint8(std::string token) {
uint32_t val = parse_uint32(token);
if (val > 0xff)
THROWMSG(InvalidIntegerException, "Integer parsing failed: Overflow");
return val;
}
static uint16_t parse_uint16(std::string token) {
uint32_t val = parse_uint32(token);
if (val > 0xffff)
THROWMSG(InvalidIntegerException, "Integer parsing failed: Overflow");
return val;
}
static std::string quote_string(const std::string unquot) {
std::string quot = unquot;
for (int i = quot.length() - 1; i >= 0; i--)
if (quot[i] == '"')
quot.replace(i, 1, "\"\"");
return quot;
}
static uint8_t parse_valid_crate(std::string token, std::string *error);
static Card *parse_valid_fru(Crate *crate, std::string token, std::string *error);
Command(std::string rawcmd, std::vector<std::string> cmd) : reapable(false), rawcmd(rawcmd), cmd(cmd), writebuf("") {
this->msgid = Command::parse_uint32(cmd[0]);
pthread_mutexattr_t attr;
assert(!pthread_mutexattr_init(&attr));
assert(!pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
assert(!pthread_mutex_init(&this->lock, &attr));
pthread_mutexattr_destroy(&attr);
};
virtual ~Command() { };
virtual uint32_t get_msgid() {
scope_lock dlock(&this->lock);
return this->msgid;
};
virtual std::string get_rawcmd() { return this->rawcmd; };
virtual bool is_reapable() {
scope_lock dlock(&this->lock, false);
if (!dlock.try_lock())
return false;
return reapable;
};
virtual enum AuthLevel get_required_privilege() { return AUTH_RAW; };
virtual uint8_t get_required_context() { return 0; };
virtual void run_here();
virtual void run_here(void *cb_null) { this->run_here(); }; // for callbacks
virtual void payload();
virtual void finalize(Client &client);
protected:
virtual void ratelimit();
};
class Client {
protected:
pthread_mutex_t lock;
int fd;
std::string readbuf;
std::string writebuf;
uint32_t next_out_msgid;
uint64_t received_bytes;
std::vector<Command*> command_queue;
std::map<uint32_t,EventFilter> event_filters;
uint32_t next_filter;
enum AuthLevel privilege;
void finalize_queue();
public:
Client(int fd)
: fd(fd), readbuf(""), writebuf(""), next_out_msgid(1),
received_bytes(0), next_filter(0), privilege(AUTH_NONE) {
pthread_mutexattr_t attr;
assert(!pthread_mutexattr_init(&attr));
assert(!pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
assert(!pthread_mutex_init(&this->lock, &attr));
pthread_mutexattr_destroy(&attr);
for (std::vector<std::string>::iterator it = config_authdata.raw.begin(); it != config_authdata.raw.end(); it++) {
if (*it == "")
this->upgrade_privilege(AUTH_RAW);
}
for (std::vector<std::string>::iterator it = config_authdata.manage.begin(); it != config_authdata.manage.end(); it++) {
if (*it == "")
this->upgrade_privilege(AUTH_MANAGE);
}
for (std::vector<std::string>::iterator it = config_authdata.read.begin(); it != config_authdata.read.end(); it++) {
if (*it == "")
this->upgrade_privilege(AUTH_READ);
}
};
int get_fd() { return this->fd; };
bool closed() { scope_lock dlock(&this->lock); return (this->fd == -1 && this->command_queue.empty()); };
bool selectable_read() { scope_lock dlock(&this->lock); return (this->fd != -1); };
bool selectable_write() {
scope_lock dlock(&this->lock);
this->finalize_queue();
return (this->fd != -1 && this->writebuf.length());
};
void selected_read();
void selected_write();
void write(std::string data);
void process_command(std::string line);
void dispatch_event(EventData event);
uint32_t get_next_out_msgid() {
scope_lock dlock(&this->lock);
uint32_t msgid = this->next_out_msgid;
this->next_out_msgid += 2;
this->next_out_msgid %= 4294967294; // (Even) MAX_UINT32-1
return msgid;
};
uint32_t register_event_filter(EventFilter filter) {
scope_lock dlock(&this->lock);
this->next_filter %= 0xffffffffull;
uint32_t filterid = ++this->next_filter;
this->event_filters.insert(std::pair<uint32_t, EventFilter>(filterid, filter));
return filterid;
}
void unregister_event_filter(uint32_t filterid) {
scope_lock dlock(&this->lock);
this->event_filters.erase(filterid);
}
std::map<uint32_t,EventFilter> get_event_filters() {
scope_lock dlock(&this->lock);
return this->event_filters;
}
void upgrade_privilege(enum AuthLevel newpriv) { scope_lock dlock(&this->lock); if (this->privilege < newpriv) this->privilege = newpriv; };
enum AuthLevel get_privilege() { scope_lock dlock(&this->lock); return this->privilege; };
};
#endif