19 mIOService(ioService),
22 mAsyncSocketBaseHandler(nullptr)
34 shared_ptr<AsyncSocketBase> _this = shared_from_this();
35 asio::dispatch(
mIOService, std::bind([_this, destination, data](){
36 _this->doSend(destination, data, 0);
43 shared_ptr<AsyncSocketBase> _this = shared_from_this();
44 asio::dispatch(
mIOService, std::bind([_this, destination, channel, data](){
45 _this->doSend(destination, channel, data, 0);
58 bool writeInProgress = !mSendDataQueue.empty();
61 mSendDataQueue.push_back(SendData(destination,
nullptr, data, bufferStartPos));
67 channel = htons(channel);
68 memcpy(&(*frame)[0], &channel, 2);
69 unsigned short msgsize = htons((
unsigned short)data->size());
70 memcpy(&(*frame)[2], (
void*)&msgsize, 2);
72 mSendDataQueue.push_back(SendData(destination, frame, data, bufferStartPos, padding));
76 sendFirstQueuedData();
89 DebugLog(<<
"handleSend with error: " << e);
95 mSendDataQueue.pop_front();
96 if (!mSendDataQueue.empty())
98 sendFirstQueuedData();
103AsyncSocketBase::sendFirstQueuedData()
105 std::vector<asio::const_buffer> bufs;
106 if (mSendDataQueue.front().mFrameData)
108 bufs.push_back(asio::buffer(mSendDataQueue.front().mFrameData->data(), mSendDataQueue.front().mFrameData->size()));
110 bufs.push_back(asio::buffer(mSendDataQueue.front().mData->data()+mSendDataQueue.front().mBufferStartPos, mSendDataQueue.front().mData->size()-mSendDataQueue.front().mBufferStartPos));
111 if (mSendDataQueue.front().mPadding)
113 static const char zeros[3] = { 0, 0, 0 };
114 bufs.push_back(asio::buffer(zeros, mSendDataQueue.front().mPadding));
116 transportSend(mSendDataQueue.front().mDestination, bufs);
149 transportFramedReceive();
166 DebugLog(<<
"handleReceive with error: " << e);
174 asio::post(
mIOService, std::bind(&AsyncSocketBase::transportClose, shared_from_this()));
177std::shared_ptr<DataBuffer>
180 return std::make_shared<DataBuffer>(size);
188 if(::setsockopt(socket.native_handle(), SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (
const char*)&on,
sizeof(on)) != 0)
190 WarningLog(<<
"Unable to set SO_EXCLUSIVEADDRUSE on a UDP socket, error=" << WSAGetLastError());
200 asio::error_code errorCode;
201 socket.close(errorCode);
205 asio::error_code ignored;
206 socket.set_option(asio::ip::tcp::no_delay(
true), ignored);
207 socket.set_option(asio::ip::tcp::socket::reuse_address(
true), ignored);
216 asyncConnectFrom(socket, endpoints, endpoints.begin(), asio::error::host_not_found);
220AsyncSocketBase::asyncConnectFrom(asio::ip::tcp::socket& socket, asio::ip::tcp::resolver::results_type endpoints,
221 asio::ip::tcp::resolver::results_type::const_iterator next, asio::error_code lastError)
223 if(next == endpoints.end())
237 const asio::ip::tcp::endpoint endpoint = *next;
238 std::shared_ptr<AsyncSocketBase> self = shared_from_this();
239 socket.async_connect(endpoint, [self, &socket, endpoints, next, endpoint](
const asio::error_code& ec)
242 if(!ec || ec == asio::error::operation_aborted)
244 self->handleConnect(ec, endpoint);
248 self->asyncConnectFrom(socket, endpoints, std::next(next), ec);
256 if(timeoutSeconds == 0)
260 mIdleTimeout = std::chrono::seconds(timeoutSeconds);
261 mInUse = std::move(inUse);
262 mIdleTimer.reset(
new asio::steady_timer(
mIOService));
264 waitIdle(mIdleTimeout);
273 mIdleTimer->cancel();
278AsyncSocketBase::waitIdle(std::chrono::steady_clock::duration wait)
283 std::weak_ptr<AsyncSocketBase> weakSelf = shared_from_this();
284 mIdleTimer->expires_after(wait);
285 mIdleTimer->async_wait([weakSelf](
const asio::error_code& e)
287 std::shared_ptr<AsyncSocketBase> self = weakSelf.lock();
288 if(e == asio::error::operation_aborted || !self || !self->mInUse)
292 const std::chrono::steady_clock::duration idle = std::chrono::steady_clock::now() - self->mLastReceived;
295 self->waitIdle(self->mIdleTimeout);
297 else if(idle < self->mIdleTimeout)
299 self->waitIdle(self->mIdleTimeout - idle);
303 InfoLog(<<
"Closing the connection from " << self->mConnectedAddress.to_string() <<
":" << self->mConnectedPort
304 <<
": nothing received for " << std::chrono::duration_cast<std::chrono::seconds>(idle).count() <<
" seconds");
virtual void doSend(const StunTuple &destination, unsigned short channel, const std::shared_ptr< DataBuffer > &data, const std::size_t bufferStartPos=0)
Use these if you already operating within the ioService thread.
void startIdleTimer(unsigned int timeoutSeconds, std::function< bool()> inUse)
For server connections (TcpConnectionIdleTimeout): the connection is closed, with close(),...