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/.
9 #include "SocketBase.h"
21 UnixSocketIOBuffer::UnixSocketIOBuffer(const void* aData
, size_t aSize
)
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
)
35 , mAvailableSpace(aAvailableSpace
)
37 mData
= new uint8_t[mAvailableSpace
];
40 UnixSocketIOBuffer::~UnixSocketIOBuffer()
44 UnixSocketIOBuffer::Consume(size_t aLen
)
46 if (NS_WARN_IF(GetSize() < aLen
)) {
49 uint8_t* data
= mData
+ mOffset
;
55 UnixSocketIOBuffer::Read(void* aValue
, size_t aLen
)
57 const uint8_t* data
= Consume(aLen
);
59 return NS_ERROR_OUT_OF_MEMORY
;
61 memcpy(aValue
, data
, aLen
);
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
);
73 mAvailableSpace
= availableSpace
;
75 uint8_t* data
= mData
+ mSize
;
81 UnixSocketIOBuffer::Write(const void* aValue
, size_t aLen
)
83 uint8_t* data
= Append(aLen
);
85 return NS_ERROR_OUT_OF_MEMORY
;
87 memcpy(data
, aValue
, aLen
);
92 UnixSocketIOBuffer::CleanupLeadingSpace()
94 if (GetLeadingSpace()) {
95 if (GetSize() <= GetLeadingSpace()) {
96 memcpy(mData
, GetData(), GetSize());
98 memmove(mData
, GetData(), GetSize());
108 UnixSocketRawData::UnixSocketRawData(const void* aData
, size_t aSize
)
109 : UnixSocketIOBuffer(aData
, aSize
)
112 UnixSocketRawData::UnixSocketRawData(size_t aSize
)
113 : UnixSocketIOBuffer(aSize
)
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();
128 TEMP_FAILURE_RETRY(read(aFd
, GetTrailingBytes(), GetTrailingSpace()));
134 /* EOF or peer shutdown sending */
138 Append(res
); /* mark read data as 'valid' */
144 UnixSocketRawData::Send(int aFd
)
150 ssize_t res
= TEMP_FAILURE_RETRY(write(aFd
, GetData(), GetSize()));
153 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
154 return 0; /* socket is blocked; try again later */
158 /* nothing written */
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
;
193 SocketBase::NotifySuccess()
195 MOZ_ASSERT(NS_IsMainThread());
197 mConnectionStatus
= SOCKET_CONNECTED
;
198 mConnectTimestamp
= PR_IntervalNow();
203 SocketBase::NotifyError()
205 MOZ_ASSERT(NS_IsMainThread());
207 mConnectionStatus
= SOCKET_DISCONNECTED
;
208 mConnectDelayMs
= CalculateConnectDelayMs();
209 mConnectTimestamp
= 0;
214 SocketBase::NotifyDisconnect()
216 MOZ_ASSERT(NS_IsMainThread());
218 mConnectionStatus
= SOCKET_DISCONNECTED
;
219 mConnectDelayMs
= CalculateConnectDelayMs();
220 mConnectTimestamp
= 0;
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...
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)
251 SocketBase::SetConnectionStatus(SocketConnectionStatus aConnectionStatus
)
253 mConnectionStatus
= aConnectionStatus
;
257 // SocketConsumerBase
260 SocketConsumerBase::~SocketConsumerBase()
267 SocketIOBase::~SocketIOBase()
271 SocketIOBase::EnqueueData(UnixSocketRawData
* aData
)
273 if (!aData
->GetSize()) {
274 delete aData
; // delete empty data immediately
277 mOutgoingQ
.AppendElement(aData
);
281 SocketIOBase::HasPendingData() const
283 return !mOutgoingQ
.IsEmpty();
286 SocketIOBase::SocketIOBase(size_t aMaxReadSize
)
287 : mMaxReadSize(aMaxReadSize
)
289 MOZ_ASSERT(mMaxReadSize
);