1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "Encoder.h"
28
29#include "DataReference.h"
30#include "MessageFlags.h"
31#include <algorithm>
32#include <stdio.h>
33
34#if OS(DARWIN)
35#include <sys/mman.h>
36#endif
37
38namespace IPC {
39
40static const uint8_t defaultMessageFlags = 0;
41
42template <typename T>
43static inline bool allocBuffer(T*& buffer, size_t size)
44{
45#if OS(DARWIN)
46 buffer = static_cast<T*>(mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0));
47 return buffer != MAP_FAILED;
48#else
49 buffer = static_cast<T*>(fastMalloc(size));
50 return !!buffer;
51#endif
52}
53
54static inline void freeBuffer(void* addr, size_t size)
55{
56#if OS(DARWIN)
57 munmap(addr, size);
58#else
59 UNUSED_PARAM(size);
60 fastFree(addr);
61#endif
62}
63
64Encoder::Encoder(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID)
65 : m_messageReceiverName(messageReceiverName)
66 , m_messageName(messageName)
67 , m_destinationID(destinationID)
68 , m_buffer(m_inlineBuffer)
69 , m_bufferPointer(m_inlineBuffer)
70 , m_bufferSize(0)
71 , m_bufferCapacity(sizeof(m_inlineBuffer))
72{
73 encodeHeader();
74}
75
76Encoder::~Encoder()
77{
78 if (m_buffer != m_inlineBuffer)
79 freeBuffer(m_buffer, m_bufferCapacity);
80 // FIXME: We need to dispose of the attachments in cases of failure.
81}
82
83bool Encoder::isSyncMessage() const
84{
85 return *buffer() & SyncMessage;
86}
87
88bool Encoder::shouldDispatchMessageWhenWaitingForSyncReply() const
89{
90 return *buffer() & DispatchMessageWhenWaitingForSyncReply;
91}
92
93void Encoder::setIsSyncMessage(bool isSyncMessage)
94{
95 if (isSyncMessage)
96 *buffer() |= SyncMessage;
97 else
98 *buffer() &= ~SyncMessage;
99}
100
101void Encoder::setShouldDispatchMessageWhenWaitingForSyncReply(bool shouldDispatchMessageWhenWaitingForSyncReply)
102{
103 if (shouldDispatchMessageWhenWaitingForSyncReply)
104 *buffer() |= DispatchMessageWhenWaitingForSyncReply;
105 else
106 *buffer() &= ~DispatchMessageWhenWaitingForSyncReply;
107}
108
109void Encoder::setFullySynchronousModeForTesting()
110{
111 *buffer() |= UseFullySynchronousModeForTesting;
112}
113
114void Encoder::wrapForTesting(std::unique_ptr<Encoder> original)
115{
116 ASSERT(isSyncMessage());
117 ASSERT(!original->isSyncMessage());
118
119 original->setShouldDispatchMessageWhenWaitingForSyncReply(true);
120
121 encodeVariableLengthByteArray(DataReference(original->buffer(), original->bufferSize()));
122
123 Vector<Attachment> attachments = original->releaseAttachments();
124 reserve(attachments.size());
125 for (Attachment& attachment : attachments)
126 addAttachment(WTFMove(attachment));
127}
128
129static inline size_t roundUpToAlignment(size_t value, unsigned alignment)
130{
131 return ((value + alignment - 1) / alignment) * alignment;
132}
133
134void Encoder::reserve(size_t size)
135{
136 if (size <= m_bufferCapacity)
137 return;
138
139 size_t newCapacity = roundUpToAlignment(m_bufferCapacity * 2, 4096);
140 while (newCapacity < size)
141 newCapacity *= 2;
142
143 uint8_t* newBuffer;
144 if (!allocBuffer(newBuffer, newCapacity))
145 CRASH();
146
147 memcpy(newBuffer, m_buffer, m_bufferSize);
148
149 if (m_buffer != m_inlineBuffer)
150 freeBuffer(m_buffer, m_bufferCapacity);
151
152 m_buffer = newBuffer;
153 m_bufferCapacity = newCapacity;
154}
155
156void Encoder::encodeHeader()
157{
158 ASSERT(!m_messageReceiverName.isEmpty());
159
160 *this << defaultMessageFlags;
161 *this << m_messageReceiverName;
162 *this << m_messageName;
163 *this << m_destinationID;
164}
165
166uint8_t* Encoder::grow(unsigned alignment, size_t size)
167{
168 size_t alignedSize = roundUpToAlignment(m_bufferSize, alignment);
169 reserve(alignedSize + size);
170
171 std::memset(m_buffer + m_bufferSize, 0, alignedSize - m_bufferSize);
172
173 m_bufferSize = alignedSize + size;
174 m_bufferPointer = m_buffer + alignedSize + size;
175
176 return m_buffer + alignedSize;
177}
178
179void Encoder::encodeFixedLengthData(const uint8_t* data, size_t size, unsigned alignment)
180{
181 ASSERT(!(reinterpret_cast<uintptr_t>(data) % alignment));
182
183 uint8_t* buffer = grow(alignment, size);
184 memcpy(buffer, data, size);
185}
186
187void Encoder::encodeVariableLengthByteArray(const DataReference& dataReference)
188{
189 encode(static_cast<uint64_t>(dataReference.size()));
190 encodeFixedLengthData(dataReference.data(), dataReference.size(), 1);
191}
192
193template<typename Type>
194static void copyValueToBuffer(Type value, uint8_t* bufferPosition)
195{
196 memcpy(bufferPosition, &value, sizeof(Type));
197}
198
199void Encoder::encode(bool n)
200{
201 uint8_t* buffer = grow(sizeof(n), sizeof(n));
202 copyValueToBuffer(n, buffer);
203}
204
205void Encoder::encode(uint8_t n)
206{
207 uint8_t* buffer = grow(sizeof(n), sizeof(n));
208 copyValueToBuffer(n, buffer);
209}
210
211void Encoder::encode(uint16_t n)
212{
213 uint8_t* buffer = grow(sizeof(n), sizeof(n));
214 copyValueToBuffer(n, buffer);
215}
216
217void Encoder::encode(uint32_t n)
218{
219 uint8_t* buffer = grow(sizeof(n), sizeof(n));
220 copyValueToBuffer(n, buffer);
221}
222
223void Encoder::encode(uint64_t n)
224{
225 uint8_t* buffer = grow(sizeof(n), sizeof(n));
226 copyValueToBuffer(n, buffer);
227}
228
229void Encoder::encode(int16_t n)
230{
231 uint8_t* buffer = grow(sizeof(n), sizeof(n));
232 copyValueToBuffer(n, buffer);
233}
234
235void Encoder::encode(int32_t n)
236{
237 uint8_t* buffer = grow(sizeof(n), sizeof(n));
238 copyValueToBuffer(n, buffer);
239}
240
241void Encoder::encode(int64_t n)
242{
243 uint8_t* buffer = grow(sizeof(n), sizeof(n));
244 copyValueToBuffer(n, buffer);
245}
246
247void Encoder::encode(float n)
248{
249 uint8_t* buffer = grow(sizeof(n), sizeof(n));
250 copyValueToBuffer(n, buffer);
251}
252
253void Encoder::encode(double n)
254{
255 uint8_t* buffer = grow(sizeof(n), sizeof(n));
256 copyValueToBuffer(n, buffer);
257}
258
259void Encoder::addAttachment(Attachment&& attachment)
260{
261 m_attachments.append(WTFMove(attachment));
262}
263
264Vector<Attachment> Encoder::releaseAttachments()
265{
266 return WTFMove(m_attachments);
267}
268
269} // namespace IPC
270