1// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <stdlib.h>
6
7#include <limits>
8
9#include "base/logging.h"
10#include "mojo/edk/system/ports/event.h"
11
12namespace mojo {
13namespace edk {
14namespace ports {
15
16// static
17bool Message::Parse(const void* bytes,
18                    size_t num_bytes,
19                    size_t* num_header_bytes,
20                    size_t* num_payload_bytes,
21                    size_t* num_ports_bytes) {
22  if (num_bytes < sizeof(EventHeader))
23    return false;
24  const EventHeader* header = static_cast<const EventHeader*>(bytes);
25  switch (header->type) {
26    case EventType::kUser:
27      // See below.
28      break;
29    case EventType::kPortAccepted:
30      *num_header_bytes = sizeof(EventHeader);
31      break;
32    case EventType::kObserveProxy:
33      *num_header_bytes = sizeof(EventHeader) + sizeof(ObserveProxyEventData);
34      break;
35    case EventType::kObserveProxyAck:
36      *num_header_bytes =
37          sizeof(EventHeader) + sizeof(ObserveProxyAckEventData);
38      break;
39    case EventType::kObserveClosure:
40      *num_header_bytes = sizeof(EventHeader) + sizeof(ObserveClosureEventData);
41      break;
42    case EventType::kMergePort:
43      *num_header_bytes = sizeof(EventHeader) + sizeof(MergePortEventData);
44      break;
45    default:
46      return false;
47  }
48
49  if (header->type == EventType::kUser) {
50    if (num_bytes < sizeof(EventHeader) + sizeof(UserEventData))
51      return false;
52    const UserEventData* event_data =
53        reinterpret_cast<const UserEventData*>(
54            reinterpret_cast<const char*>(header + 1));
55    if (event_data->num_ports > std::numeric_limits<uint16_t>::max())
56      return false;
57    *num_header_bytes = sizeof(EventHeader) +
58                        sizeof(UserEventData) +
59                        event_data->num_ports * sizeof(PortDescriptor);
60    *num_ports_bytes = event_data->num_ports * sizeof(PortName);
61    if (num_bytes < *num_header_bytes + *num_ports_bytes)
62      return false;
63    *num_payload_bytes = num_bytes - *num_header_bytes - *num_ports_bytes;
64  } else {
65    if (*num_header_bytes != num_bytes)
66      return false;
67    *num_payload_bytes = 0;
68    *num_ports_bytes = 0;
69  }
70
71  return true;
72}
73
74Message::Message(size_t num_payload_bytes, size_t num_ports)
75    : Message(sizeof(EventHeader) + sizeof(UserEventData) +
76                  num_ports * sizeof(PortDescriptor),
77              num_payload_bytes, num_ports * sizeof(PortName)) {
78  num_ports_ = num_ports;
79}
80
81Message::Message(size_t num_header_bytes,
82                 size_t num_payload_bytes,
83                 size_t num_ports_bytes)
84    : start_(nullptr),
85      num_header_bytes_(num_header_bytes),
86      num_ports_bytes_(num_ports_bytes),
87      num_payload_bytes_(num_payload_bytes) {
88}
89
90void Message::InitializeUserMessageHeader(void* start) {
91  start_ = static_cast<char*>(start);
92  memset(start_, 0, num_header_bytes_);
93  GetMutableEventHeader(this)->type = EventType::kUser;
94  GetMutableEventData<UserEventData>(this)->num_ports =
95      static_cast<uint32_t>(num_ports_);
96}
97
98}  // namespace ports
99}  // namespace edk
100}  // namespace mojo
101