Fix typo in 9b54bd30006c008b4a951331b273613d5bac3abf
[pm.git] / ipc / unixsocket / SocketBase.cpp
blobeb0607c34841e3cda67ba6c0d058fa57bd36e953
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 */
9 #include "SocketBase.h"
10 #include <errno.h>
11 #include <string.h>
12 #include <unistd.h>
14 namespace mozilla {
15 namespace ipc {
18 // UnixSocketIOBuffer
21 UnixSocketIOBuffer::UnixSocketIOBuffer(const void* aData, size_t aSize)
22 : mSize(aSize)
23 , mOffset(0)
24 , mAvailableSpace(aSize)
26 MOZ_ASSERT(aData || !mSize);
28 mData = new uint8_t[mAvailableSpace];
29 memcpy(mData, aData, mSize);
32 UnixSocketIOBuffer::UnixSocketIOBuffer(size_t aAvailableSpace)
33 : mSize(0)
34 , mOffset(0)
35 , mAvailableSpace(aAvailableSpace)
37 mData = new uint8_t[mAvailableSpace];
40 UnixSocketIOBuffer::~UnixSocketIOBuffer()
41 { }
43 const uint8_t*
44 UnixSocketIOBuffer::Consume(size_t aLen)
46 if (NS_WARN_IF(GetSize() < aLen)) {
47 return nullptr;
49 uint8_t* data = mData + mOffset;
50 mOffset += aLen;
51 return data;
54 nsresult
55 UnixSocketIOBuffer::Read(void* aValue, size_t aLen)
57 const uint8_t* data = Consume(aLen);
58 if (!data) {
59 return NS_ERROR_OUT_OF_MEMORY;
61 memcpy(aValue, data, aLen);
62 return NS_OK;
65 uint8_t*
66 UnixSocketIOBuffer::Append(size_t aLen)
68 if (((mAvailableSpace - mSize) < aLen)) {
69 size_t availableSpace = mAvailableSpace + std::max(mAvailableSpace, aLen);
70 uint8_t* data = new uint8_t[availableSpace];
71 memcpy(data, mData, mSize);
72 mData = data;
73 mAvailableSpace = availableSpace;
75 uint8_t* data = mData + mSize;
76 mSize += aLen;
77 return data;
80 nsresult
81 UnixSocketIOBuffer::Write(const void* aValue, size_t aLen)
83 uint8_t* data = Append(aLen);
84 if (!data) {
85 return NS_ERROR_OUT_OF_MEMORY;
87 memcpy(data, aValue, aLen);
88 return NS_OK;
91 void
92 UnixSocketIOBuffer::CleanupLeadingSpace()
94 if (GetLeadingSpace()) {
95 if (GetSize() <= GetLeadingSpace()) {
96 memcpy(mData, GetData(), GetSize());
97 } else {
98 memmove(mData, GetData(), GetSize());
100 mOffset = 0;
105 // UnixSocketRawData
108 UnixSocketRawData::UnixSocketRawData(const void* aData, size_t aSize)
109 : UnixSocketIOBuffer(aData, aSize)
112 UnixSocketRawData::UnixSocketRawData(size_t aSize)
113 : UnixSocketIOBuffer(aSize)
116 ssize_t
117 UnixSocketRawData::Receive(int aFd)
119 if (!GetTrailingSpace()) {
120 if (!GetLeadingSpace()) {
121 return -1; /* buffer is full */
123 /* free up space at the end of data buffer */
124 CleanupLeadingSpace();
127 ssize_t res =
128 TEMP_FAILURE_RETRY(read(aFd, GetTrailingBytes(), GetTrailingSpace()));
130 if (res < 0) {
131 /* I/O error */
132 return -1;
133 } else if (!res) {
134 /* EOF or peer shutdown sending */
135 return 0;
138 Append(res); /* mark read data as 'valid' */
140 return res;
143 ssize_t
144 UnixSocketRawData::Send(int aFd)
146 if (!GetSize()) {
147 return 0;
150 ssize_t res = TEMP_FAILURE_RETRY(write(aFd, GetData(), GetSize()));
152 if (res < 0) {
153 if (errno == EAGAIN || errno == EWOULDBLOCK) {
154 return 0; /* socket is blocked; try again later */
156 return -1;
157 } else if (!res) {
158 /* nothing written */
159 return 0;
162 Consume(res);
164 return res;
168 // SocketBase
171 SocketBase::~SocketBase()
173 MOZ_ASSERT(mConnectionStatus == SOCKET_DISCONNECTED);
176 SocketConnectionStatus
177 SocketBase::GetConnectionStatus() const
179 MOZ_ASSERT(NS_IsMainThread());
181 return mConnectionStatus;
185 SocketBase::GetSuggestedConnectDelayMs() const
187 MOZ_ASSERT(NS_IsMainThread());
189 return mConnectDelayMs;
192 void
193 SocketBase::NotifySuccess()
195 MOZ_ASSERT(NS_IsMainThread());
197 mConnectionStatus = SOCKET_CONNECTED;
198 mConnectTimestamp = PR_IntervalNow();
199 OnConnectSuccess();
202 void
203 SocketBase::NotifyError()
205 MOZ_ASSERT(NS_IsMainThread());
207 mConnectionStatus = SOCKET_DISCONNECTED;
208 mConnectDelayMs = CalculateConnectDelayMs();
209 mConnectTimestamp = 0;
210 OnConnectError();
213 void
214 SocketBase::NotifyDisconnect()
216 MOZ_ASSERT(NS_IsMainThread());
218 mConnectionStatus = SOCKET_DISCONNECTED;
219 mConnectDelayMs = CalculateConnectDelayMs();
220 mConnectTimestamp = 0;
221 OnDisconnect();
224 uint32_t
225 SocketBase::CalculateConnectDelayMs() const
227 MOZ_ASSERT(NS_IsMainThread());
229 uint32_t connectDelayMs = mConnectDelayMs;
231 if (mConnectTimestamp && (PR_IntervalNow()-mConnectTimestamp) > connectDelayMs) {
232 // reset delay if connection has been opened for a while, or...
233 connectDelayMs = 0;
234 } else if (!connectDelayMs) {
235 // ...start with a delay of ~1 sec, or...
236 connectDelayMs = 1<<10;
237 } else if (connectDelayMs < (1<<16)) {
238 // ...otherwise increase delay by a factor of 2
239 connectDelayMs <<= 1;
241 return connectDelayMs;
244 SocketBase::SocketBase()
245 : mConnectionStatus(SOCKET_DISCONNECTED)
246 , mConnectTimestamp(0)
247 , mConnectDelayMs(0)
250 void
251 SocketBase::SetConnectionStatus(SocketConnectionStatus aConnectionStatus)
253 mConnectionStatus = aConnectionStatus;
257 // SocketConsumerBase
260 SocketConsumerBase::~SocketConsumerBase()
264 // SocketIOBase
267 SocketIOBase::~SocketIOBase()
270 void
271 SocketIOBase::EnqueueData(UnixSocketRawData* aData)
273 if (!aData->GetSize()) {
274 delete aData; // delete empty data immediately
275 return;
277 mOutgoingQ.AppendElement(aData);
280 bool
281 SocketIOBase::HasPendingData() const
283 return !mOutgoingQ.IsEmpty();
286 SocketIOBase::SocketIOBase(size_t aMaxReadSize)
287 : mMaxReadSize(aMaxReadSize)
289 MOZ_ASSERT(mMaxReadSize);