Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(615)

Side by Side Diff: pkg/fletch_agent/lib/messages.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/fletch_agent/lib/agent_connection.dart ('k') | pkg/fletch_agent/tool/client.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE.md file.
4
5 /// This comment describes the Fletch Agent's request and reply message format.
6 ///
7 /// Message requests all start with the following header:
8 ///
9 /// -----------------------------------------
10 /// | Command (16 bits) | Version (16 bits) |
11 /// -----------------------------------------
12 /// | Msg ID (16 bits) | Unused (16 bits) |
13 /// -----------------------------------------
14 /// | Payload Length (32 bits) |
15 /// -----------------------------------------
16 ///
17 /// Field descriptions:
18 ///
19 /// Command: Identifies the requested action.
20 /// Version: used to determine if the server supports the client's request.
21 /// Msg ID: used to correlate a reply with the sender.
22 /// Unused: Reserved for future uses.
23 /// Payload Length: Length of request payload in bytes.
24 ///
25 /// The request header is immediately followed by the relevant payload data for
26 /// the given command. See details for payloads below.
27 ///
28 /// All requests have a related reply with the following reply header.
29 ///
30 /// ---------------------------------------
31 /// | Msg ID (16 bits) | Result (16 bits) |
32 /// ---------------------------------------
33 /// | Payload Length (32 bits) |
34 /// ---------------------------------------
35 ///
36 /// Field descriptions:
37 ///
38 /// Msg ID: used to correlate a reply with the sender.
39 /// Result: Can be success (0) or failure (a positive number).
40 /// Payload length: Length of reply payload in bytes.
41 ///
42 /// The reply header is immediately followed by the relevant payload data for
43 /// the related request's command. See details for payloads below.
44 ///
45 /// Command descriptions:
46 ///
47 /// Below follows a description of request/reply payloads for a given command.
48 /// Each payload is always preceded by the corresponding header.
49 ///
50 /// START_VM:
51 /// Start a new Fletch VM and return the vm's id and port on which it is
52 /// listening.
53 /// Request Payload:
54 /// None.
55 /// Reply Payload on success:
56 /// ---------------------
57 /// | VM ID (32 bits) |
58 /// ---------------------
59 /// | VM Port (32 bits) |
60 /// ---------------------
61 /// Reply Payload on failure:
62 /// None.
63 ///
64 /// STOP_VM:
65 /// Stop the VM specified by the given vm id.
66 /// Request Payload:
67 /// ---------------------
68 /// | VM ID (32 bits) |
69 /// ---------------------
70 /// Reply Payload on success:
71 /// None.
72 /// Reply Payload on failure:
73 /// None.
74 ///
75 /// LIST_VMS:
76 /// This command lists the currently running Fletch VMs.
77 /// Request Payload:
78 /// None.
79 /// Reply Payload on success:
80 /// ---------------------
81 /// | VM ID (32 bits) |
82 /// ---------------------
83 /// | VM ID (32 bits) |
84 /// ---------------------
85 /// | VM ID (32 bits) |
86 /// ---------------------
87 /// ...
88 ///
89 /// Reply Payload on failure:
90 /// None.
91 ///
92 /// UPGRADE_VM:
93 /// This command is used to update the Fletch VM binary on the device.
94 /// Request Payload:
95 /// ... the vm binary bytes
96 ///
97 /// Reply Payload on success:
98 /// None.
99 /// Reply Payload on failure:
100 /// None.
101
102 library fletch_agent.messages;
103
104 import 'dart:convert' show ASCII;
105 import 'dart:typed_data';
106
107 /// Current Fletch Agent version
108 const int AGENT_VERSION = 1;
109
110 /// Default agent port
111 const int AGENT_DEFAULT_PORT = 12121;
112
113 /// Temporary path for the agent package used during upgrade.
114 const String PACKAGE_FILE_NAME = '/tmp/fletch-agent.deb';
115
116 class RequestHeader {
117 static const int START_VM = 0;
118 static const int STOP_VM = 1;
119 static const int LIST_VMS = 2;
120 static const int UPGRADE_AGENT = 3;
121 static const int FLETCH_VERSION = 4;
122 static const int SIGNAL_VM = 5;
123
124 // Wire size (bytes) of the RequestHeader.
125 static const int HEADER_SIZE = 12;
126
127 static int _nextMessageId = 1;
128 static int get nextMessageId {
129 if ((_nextMessageId & 0xFFFF) == 0) {
130 _nextMessageId = 1;
131 }
132 return _nextMessageId++;
133 }
134
135 final int command;
136 final int version;
137 final int id;
138 final int reserved;
139 final int payloadLength;
140
141 RequestHeader(
142 this.command,
143 {this.version: AGENT_VERSION,
144 int id,
145 this.reserved: 0,
146 this.payloadLength: 0})
147 : id = id != null ? id : nextMessageId;
148
149 factory RequestHeader.fromBuffer(ByteBuffer buffer) {
150 if (buffer.lengthInBytes < HEADER_SIZE) {
151 throw new MessageDecodeException(
152 'Insufficient bytes (${buffer.lengthInBytes}) to decode header: '
153 '${buffer.asUint8List()})');
154 }
155 // The network byte order is big endian.
156 int cmd = readUint16(buffer, 0);
157 int version = readUint16(buffer, 2);
158 int id = readUint16(buffer, 4);
159 int reserved = readUint16(buffer, 6);
160 int payloadLength = readUint32(buffer, 8);
161 return new RequestHeader(cmd, version: version, id: id, reserved: reserved,
162 payloadLength: payloadLength);
163 }
164
165 ByteBuffer toBuffer() {
166 var buffer = new Uint8List(HEADER_SIZE).buffer;
167 _writeHeader(buffer);
168 return buffer;
169 }
170
171 void _writeHeader(ByteBuffer buffer) {
172 writeUint16(buffer, 0, command);
173 writeUint16(buffer, 2, version);
174 writeUint16(buffer, 4, id);
175 writeUint16(buffer, 6, reserved);
176 writeUint32(buffer, 8, payloadLength);
177 }
178 }
179
180 class StartVmRequest extends RequestHeader {
181 StartVmRequest() : super(RequestHeader.START_VM);
182
183 StartVmRequest.withHeader(RequestHeader header)
184 : super(
185 RequestHeader.START_VM,
186 version: header.version,
187 id: header.id,
188 reserved: header.reserved);
189
190 factory StartVmRequest.fromBuffer(ByteBuffer buffer) {
191 var header = new RequestHeader.fromBuffer(buffer);
192 assert(header != null);
193 if (header.command != RequestHeader.START_VM || header.payloadLength != 0) {
194 throw new MessageDecodeException(
195 "Invalid StartVmRequest: ${buffer.asUint8List()}");
196 }
197 return new StartVmRequest.withHeader(header);
198 }
199
200 // A StartVmRequest has no payload so just use parent's toBuffer method.
201 }
202
203 class StopVmRequest extends RequestHeader {
204 final int vmPid;
205
206 StopVmRequest(this.vmPid)
207 : super(RequestHeader.STOP_VM, payloadLength: 4);
208
209 StopVmRequest.withHeader(RequestHeader header, this.vmPid)
210 : super(
211 RequestHeader.STOP_VM,
212 version: header.version,
213 id: header.id,
214 reserved: header.reserved);
215
216 factory StopVmRequest.fromBuffer(ByteBuffer buffer) {
217 if (buffer.lengthInBytes < RequestHeader.HEADER_SIZE + 4) {
218 throw new MessageDecodeException(
219 'Insufficient data for a StopVmRequest: ${buffer.asUint8List()}');
220 }
221 var header = new RequestHeader.fromBuffer(buffer);
222 if (header.command != RequestHeader.STOP_VM || header.payloadLength != 4) {
223 throw new MessageDecodeException(
224 "Invalid StopVmRequest: ${buffer.asUint8List()}");
225 }
226 var vmPid = readUint32(buffer, RequestHeader.HEADER_SIZE);
227 return new StopVmRequest.withHeader(header, vmPid);
228 }
229
230 ByteBuffer toBuffer() {
231 var buffer = new Uint8List(RequestHeader.HEADER_SIZE + 4).buffer;
232 _writeHeader(buffer);
233 writeUint32(buffer, RequestHeader.HEADER_SIZE, vmPid);
234 return buffer;
235 }
236 }
237
238 class ListVmsRequest extends RequestHeader {
239 ListVmsRequest() : super(RequestHeader.LIST_VMS);
240
241 ListVmsRequest.withHeader(RequestHeader header)
242 : super(
243 RequestHeader.LIST_VMS,
244 version: header.version,
245 id: header.id,
246 reserved: header.reserved);
247
248 factory ListVmsRequest.fromBuffer(ByteBuffer buffer) {
249 var header = new RequestHeader.fromBuffer(buffer);
250 if (header.command != RequestHeader.LIST_VMS || header.payloadLength != 0) {
251 throw new MessageDecodeException(
252 "Invalid ListVmsRequest: ${buffer.asUint8List()}");
253 }
254 return new ListVmsRequest.withHeader(header);
255 }
256
257 // A ListVmsRequest has no payload so just use parent's toBuffer method.
258 }
259
260 class UpgradeAgentRequest extends RequestHeader {
261 final List<int> binary;
262
263 UpgradeAgentRequest(List<int> binary)
264 : super(RequestHeader.UPGRADE_AGENT, payloadLength: binary.length),
265 binary = binary;
266
267 UpgradeAgentRequest.withHeader(RequestHeader header, List<int> binary)
268 : super(
269 RequestHeader.UPGRADE_AGENT,
270 version: header.version,
271 id: header.id,
272 reserved: header.reserved,
273 payloadLength: binary.length),
274 binary = binary;
275
276 factory UpgradeAgentRequest.fromBuffer(ByteBuffer buffer) {
277 var header = new RequestHeader.fromBuffer(buffer);
278 if (header.command != RequestHeader.UPGRADE_AGENT) {
279 throw new MessageDecodeException(
280 'Invalid UpgradeVmRequest: ${buffer.asUint8List()}');
281 }
282 // TODO(wibling): figure out how to best represent the vm binary data.
283 // The below has issues since the list view is offset and hence using
284 // the underlying buffer requires the user to know the buffer is not the
285 // same length as the list.
286 var binary = buffer.asUint8List(RequestHeader.HEADER_SIZE);
287 return new UpgradeAgentRequest.withHeader(header, binary);
288 }
289
290 ByteBuffer toBuffer() {
291 var bytes =
292 new Uint8List(RequestHeader.HEADER_SIZE + binary.length);
293 _writeHeader(bytes.buffer);
294 // TODO(wibling): This does a copy of the vm binary. Try to avoid that.
295 for (int i = 0; i < binary.length; ++i) {
296 bytes[RequestHeader.HEADER_SIZE + i] = binary[i];
297 }
298 return bytes.buffer;
299 }
300 }
301
302 class FletchVersionRequest extends RequestHeader {
303 FletchVersionRequest()
304 : super(RequestHeader.FLETCH_VERSION);
305
306 FletchVersionRequest.withHeader(RequestHeader header)
307 : super(
308 RequestHeader.FLETCH_VERSION,
309 version: header.version,
310 id: header.id,
311 reserved: header.reserved);
312
313 factory FletchVersionRequest.fromBuffer(ByteBuffer buffer) {
314 var header = new RequestHeader.fromBuffer(buffer);
315 if (header.command != RequestHeader.FLETCH_VERSION ||
316 header.payloadLength != 0) {
317 throw new MessageDecodeException(
318 'Invalid FletchVersionRequest: ${buffer.asUint8List()}');
319 }
320 return new FletchVersionRequest.withHeader(header);
321 }
322
323 // A FletchVersionRequest has no payload so just use parent's toBuffer method.
324 }
325
326 class SignalVmRequest extends RequestHeader {
327 final int vmPid;
328 final int signal;
329
330 SignalVmRequest(this.vmPid, this.signal)
331 : super(RequestHeader.SIGNAL_VM, payloadLength: 8);
332
333 SignalVmRequest.withHeader(RequestHeader header, this.vmPid, this.signal)
334 : super(
335 RequestHeader.SIGNAL_VM,
336 version: header.version,
337 id: header.id,
338 reserved: header.reserved);
339
340 factory SignalVmRequest.fromBuffer(ByteBuffer buffer) {
341 if (buffer.lengthInBytes < RequestHeader.HEADER_SIZE + 8) {
342 throw new MessageDecodeException(
343 'Insufficient data for a SignalVmRequest: ${buffer.asUint8List()}');
344 }
345 RequestHeader header = new RequestHeader.fromBuffer(buffer);
346 if (header.command != RequestHeader.SIGNAL_VM ||
347 header.payloadLength != 8) {
348 throw new MessageDecodeException(
349 "Invalid SignalVmRequest: ${buffer.asUint8List()}");
350 }
351 int vmPid = readUint32(buffer, RequestHeader.HEADER_SIZE);
352 int signal = readUint32(buffer, RequestHeader.HEADER_SIZE + 4);
353 return new SignalVmRequest.withHeader(header, vmPid, signal);
354 }
355
356 ByteBuffer toBuffer() {
357 var buffer = new Uint8List(RequestHeader.HEADER_SIZE + 8).buffer;
358 _writeHeader(buffer);
359 writeUint32(buffer, RequestHeader.HEADER_SIZE, vmPid);
360 writeUint32(buffer, RequestHeader.HEADER_SIZE + 4, signal);
361 return buffer;
362 }
363 }
364
365 class ReplyHeader {
366 /// Error codes.
367 static const int SUCCESS = 0;
368 static const int UNKNOWN_COMMAND = 1;
369 static const int INVALID_PAYLOAD = 2;
370 static const int UNSUPPORTED_VERSION = 3;
371 static const int START_VM_FAILED = 4;
372 static const int UNKNOWN_VM_ID = 5;
373 static const int UPGRADE_FAILED = 6;
374
375 // Wire size (bytes) of the ReplyHeader.
376 static const int HEADER_SIZE = 8;
377
378 final int id;
379 final int result;
380 final int payloadLength;
381
382 ReplyHeader(this.id, this.result, {this.payloadLength: 0});
383
384 factory ReplyHeader.fromBuffer(ByteBuffer buffer) {
385 if (buffer == null || buffer.lengthInBytes < HEADER_SIZE) {
386 throw new MessageDecodeException(
387 'Insufficient data for a ReplyHeader: ${buffer.asUint8List()}');
388 }
389 var id = readUint16(buffer, 0);
390 var result = readUint16(buffer, 2);
391 var payloadLength = readUint32(buffer, 4);
392 return new ReplyHeader(id, result, payloadLength: payloadLength);
393 }
394
395 ByteBuffer toBuffer() {
396 var buffer = new Uint8List(HEADER_SIZE).buffer;
397 _writeHeader(buffer);
398 return buffer;
399 }
400
401 void _writeHeader(ByteBuffer buffer) {
402 writeUint16(buffer, 0, id);
403 writeUint16(buffer, 2, result);
404 writeUint32(buffer, 4, payloadLength);
405 }
406 }
407
408 class StartVmReply extends ReplyHeader {
409 final int vmId;
410 final int vmPort;
411
412 StartVmReply(int id, int result, {this.vmId, this.vmPort})
413 : super(
414 id,
415 result,
416 payloadLength: result == ReplyHeader.SUCCESS ? 8 : 0);
417
418 factory StartVmReply.fromBuffer(ByteBuffer buffer) {
419 var header = new ReplyHeader.fromBuffer(buffer);
420 int vmId;
421 int vmPort;
422 if (header.result == ReplyHeader.SUCCESS) {
423 // There must be 8 bytes of payload.
424 if (buffer.lengthInBytes < ReplyHeader.HEADER_SIZE + 8 ||
425 header.payloadLength != 8) {
426 throw new MessageDecodeException(
427 "Invalid StartVmReply: ${buffer.asUint8List()}");
428 }
429 vmId = readUint32(buffer, ReplyHeader.HEADER_SIZE);
430 vmPort = readUint32(buffer, ReplyHeader.HEADER_SIZE + 4);
431 }
432 return new StartVmReply(
433 header.id, header.result, vmId: vmId, vmPort: vmPort);
434 }
435
436 ByteBuffer toBuffer() {
437 ByteBuffer buffer;
438 if (result == ReplyHeader.SUCCESS) {
439 buffer = new Uint8List(ReplyHeader.HEADER_SIZE + 8).buffer;
440 _writeHeader(buffer);
441 writeUint32(buffer, ReplyHeader.HEADER_SIZE, vmId);
442 writeUint32(buffer, ReplyHeader.HEADER_SIZE + 4, vmPort);
443 } else {
444 buffer = new Uint8List(ReplyHeader.HEADER_SIZE).buffer;
445 _writeHeader(buffer);
446 }
447 return buffer;
448 }
449 }
450
451 class StopVmReply extends ReplyHeader {
452 StopVmReply(int id, int result) : super(id, result);
453
454 factory StopVmReply.fromBuffer(ByteBuffer buffer) {
455 ReplyHeader header = new ReplyHeader.fromBuffer(buffer);
456 if (header.payloadLength != 0) {
457 throw new MessageDecodeException(
458 "Invalid payload length in StopVmReply: ${buffer.asUint8List()}");
459 }
460 return new StopVmReply(header.id, header.result);
461 }
462
463 // The STOP_VM reply has no payload, so leverage parent's toBuffer method.
464 }
465
466 class ListVmsReply extends ReplyHeader {
467 final List<int> vmIds;
468
469 ListVmsReply(int id, int result, {List<int> vmIds})
470 : super(id, result, payloadLength: vmIds != null ? vmIds.length * 4 : 0),
471 vmIds = vmIds;
472
473 factory ListVmsReply.fromBuffer(ByteBuffer buffer) {
474 var header = new ReplyHeader.fromBuffer(buffer);
475 List<int> vmIds = [];
476 if (header.result == ReplyHeader.SUCCESS) {
477 for (int i = 0; i < header.payloadLength ~/ 4; ++i) {
478 vmIds.add(readUint32(buffer, ReplyHeader.HEADER_SIZE + (i * 4)));
479 }
480 }
481 return new ListVmsReply(header.id, header.result, vmIds: vmIds);
482 }
483
484 ByteBuffer toBuffer() {
485 ByteBuffer buffer;
486 if (result == ReplyHeader.SUCCESS) {
487 int numVms = vmIds != null ? vmIds.length : 0;
488 buffer = new Uint8List(ReplyHeader.HEADER_SIZE + (numVms * 4)).buffer;
489 _writeHeader(buffer);
490 for (int i = 0; i < numVms; ++i) {
491 writeUint32(buffer, ReplyHeader.HEADER_SIZE + (i * 4), vmIds[i]);
492 }
493 } else {
494 buffer = new Uint8List(ReplyHeader.HEADER_SIZE).buffer;
495 _writeHeader(buffer);
496 }
497 return buffer;
498 }
499 }
500
501 class UpgradeAgentReply extends ReplyHeader {
502
503 UpgradeAgentReply(int id, int result) : super(id, result);
504
505 factory UpgradeAgentReply.fromBuffer(ByteBuffer buffer) {
506 ReplyHeader header = new ReplyHeader.fromBuffer(buffer);
507 if (header.payloadLength != 0) {
508 throw new MessageDecodeException(
509 "Invalid payload length in UpgradeAgentReply: ${buffer.asUint8List()}" );
510 }
511 return new UpgradeAgentReply(header.id, header.result);
512 }
513
514 // The UPGRADE_AGENT reply has no payload, so leverage parent's toBuffer metho d.
515 }
516
517 class FletchVersionReply extends ReplyHeader {
518 final String fletchVersion;
519
520 FletchVersionReply(int id, int result, {String version})
521 : super(id, result, payloadLength: version != null ? version.length : 0),
522 fletchVersion = version {
523 if (result == ReplyHeader.SUCCESS && version == null) {
524 throw new MessageEncodeException(
525 "Missing version for FletchVersionReply.");
526 }
527 }
528
529 factory FletchVersionReply.fromBuffer(ByteBuffer buffer) {
530 var header = new ReplyHeader.fromBuffer(buffer);
531 String version;
532 if (header.result == ReplyHeader.SUCCESS) {
533 int payloadLength = header.payloadLength;
534 if (payloadLength == 0 ||
535 buffer.lengthInBytes < ReplyHeader.HEADER_SIZE + payloadLength) {
536 throw new MessageDecodeException(
537 "Invalid FletchVersionReply: ${buffer.asUint8List()}");
538 }
539 version = ASCII.decode(buffer.asUint8List(ReplyHeader.HEADER_SIZE));
540 }
541 return new FletchVersionReply(header.id, header.result, version: version);
542 }
543
544 ByteBuffer toBuffer() {
545 ByteBuffer buffer;
546 if (result == ReplyHeader.SUCCESS) {
547 Uint8List message = new Uint8List(
548 ReplyHeader.HEADER_SIZE + fletchVersion.length);
549 _writeHeader(message.buffer);
550 List<int> encodedVersion = ASCII.encode(fletchVersion);
551 assert(encodedVersion != null);
552 assert(fletchVersion.length == encodedVersion.length);
553 message.setRange(
554 ReplyHeader.HEADER_SIZE,
555 ReplyHeader.HEADER_SIZE + encodedVersion.length,
556 encodedVersion);
557 buffer = message.buffer;
558 } else {
559 buffer = new Uint8List(ReplyHeader.HEADER_SIZE).buffer;
560 _writeHeader(buffer);
561 }
562 return buffer;
563 }
564 }
565
566 class SignalVmReply extends ReplyHeader {
567 SignalVmReply(int id, int result)
568 : super(id, result);
569
570 factory SignalVmReply.fromBuffer(ByteBuffer buffer) {
571 ReplyHeader header = new ReplyHeader.fromBuffer(buffer);
572 if (header.payloadLength != 0) {
573 throw new MessageDecodeException(
574 "Invalid payload length in SignalVmReply: ${buffer.asUint8List()}");
575 }
576 return new SignalVmReply(header.id, header.result);
577 }
578
579 // The SIGNAL_VM reply has no payload, so leverage parent's toBuffer method.
580 // TODO(wibling): Figure out how to return exitcode from vm on exit.
581 }
582
583 // Utility methods to read and write 16 and 32 bit entities from/to big endian.
584 int readUint16(ByteBuffer buffer, int offset) {
585 // Goto right offset
586 var b = buffer.asUint8List(offset, 2);
587 return b[0] << 8 | b[1];
588 }
589
590 void writeUint16(ByteBuffer buffer, int offset, int value) {
591 // Goto right offset
592 var b = buffer.asUint8List(offset, 2);
593 b[0] = value >> 8 & 0xff;
594 b[1] = value & 0xff;
595 }
596
597 int readUint32(ByteBuffer buffer, int offset) {
598 // Goto right offset
599 var b = buffer.asUint8List(offset, 4);
600 return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
601 }
602
603 void writeUint32(ByteBuffer buffer, int offset, int value) {
604 // Goto right offset
605 var b = buffer.asUint8List(offset, 4);
606 b[0] = value >> 24 & 0xff;
607 b[1] = value >> 16 & 0xff;
608 b[2] = value >> 8 & 0xff;
609 b[3] = value & 0xff;
610 }
611
612 class MessageDecodeException implements Exception {
613 final String message;
614 MessageDecodeException(this.message);
615 String toString() => 'MessageDecodeException($message)';
616 }
617
618 class MessageEncodeException implements Exception {
619 final String message;
620 MessageEncodeException(this.message);
621 String toString() => 'MessageEncodeException($message)';
622 }
OLDNEW
« no previous file with comments | « pkg/fletch_agent/lib/agent_connection.dart ('k') | pkg/fletch_agent/tool/client.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698