void OnReceived(_UInt32 nbytes, StreamBuffer::Node* node, const error_code& error) { m_PendingRecvRequestCount--; node->m_Len = nbytes; m_Wrapper->m_IStream.PushNode(node); if (error.value() != 0) { if (m_PendingRecvRequestCount == 0 && m_RequestSendRequestCount == 0) { if (!(error.value() == 104 || error.value() == 54)) { m_Wrapper->Close(); } if (!m_Wrapper->m_OnConnectBroken.Empty()) { m_Wrapper->m_OnConnectBroken(m_Wrapper, m_Wrapper->m_IStream, m_Wrapper->m_OStream); } } } else { AsyncReceive(); m_Wrapper->m_OnReceived(m_Wrapper, m_Wrapper->m_IStream, m_Wrapper->m_OStream); } }
bool SkyLinesTracking::Client::Open(boost::asio::ip::udp::endpoint _endpoint) { Close(); endpoint = _endpoint; boost::system::error_code ec; socket.open(endpoint.protocol(), ec); if (ec) return false; if (handler != nullptr) { AsyncReceive(); handler->OnSkyLinesReady(); } return true; }
void Server::OnReceive(const boost::system::error_code &ec, size_t size) { // TODO: use recvmmsg() on Linux if (ec) { if (ec == boost::asio::error::operation_aborted) return; socket.close(); OnError(boost::system::system_error(ec)); return; } OnDatagramReceived(std::move(client_buffer), buffer, size); AsyncReceive(); }
void OnConnected(const std::string& remote, _UInt16 port, const error_code& error) { if (error.value() == 0) { m_Wrapper->m_IStream.Clear(); // Hack by hailong for re-connection m_Wrapper->m_OStream.Clear(); CloseLinger(); AsyncReceive(); m_Wrapper->m_OnConnected(m_Wrapper, m_Wrapper->m_IStream, m_Wrapper->m_OStream); } else { m_Wrapper->m_Errno = IGAME_ERROR_CONNECT; m_Socket.close(); if (!m_Wrapper->m_OnConnectFailed.Empty()) { m_Wrapper->m_OnConnectFailed(m_Wrapper, m_Wrapper->m_IStream, m_Wrapper->m_OStream); } } }
void AddressBookSubscription::Request () { // must be run in separate thread LogPrint (eLogInfo, "Downloading hosts from ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified); bool success = false; i2p::util::http::url u (m_Link); i2p::data::IdentHash ident; if (m_Book.GetIdentHash (u.host_, ident)) { std::condition_variable newDataReceived; std::mutex newDataReceivedMutex; auto leaseSet = m_Book.getSharedLocalDestination()->FindLeaseSet (ident); if (!leaseSet) { std::unique_lock<std::mutex> l(newDataReceivedMutex); m_Book.getSharedLocalDestination()->RequestDestination (ident, [&newDataReceived, &leaseSet](std::shared_ptr<i2p::data::LeaseSet> ls) { leaseSet = ls; newDataReceived.notify_all (); }); if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) LogPrint (eLogError, "Subscription LeseseSet request timeout expired"); } if (leaseSet) { std::stringstream request, response; // standard header request << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n"; if (m_Etag.length () > 0) // etag request << i2p::util::http::IF_NONE_MATCH << ": \"" << m_Etag << "\"\r\n"; if (m_LastModified.length () > 0) // if-modfief-since request << i2p::util::http::IF_MODIFIED_SINCE << ": " << m_LastModified << "\r\n"; request << "\r\n"; // end of header auto stream = m_Book.getSharedLocalDestination()->CreateStream (leaseSet, u.port_); stream->Send ((uint8_t *)request.str ().c_str (), request.str ().length ()); uint8_t buf[4096]; bool end = false; while (!end) { stream->AsyncReceive (boost::asio::buffer (buf, 4096), [&](const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (bytes_transferred) response.write ((char *)buf, bytes_transferred); if (ecode == boost::asio::error::timed_out || !stream->IsOpen ()) end = true; newDataReceived.notify_all (); }, 30); // wait for 30 seconds std::unique_lock<std::mutex> l(newDataReceivedMutex); if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) LogPrint (eLogError, "Subscription timeout expired"); } // process remaining buffer while (size_t len = stream->ReadSome (buf, 4096)) response.write ((char *)buf, len); // parse response std::string version; response >> version; // HTTP version int status = 0; response >> status; // status if (status == 200) // OK { bool isChunked = false; std::string header, statusMessage; std::getline (response, statusMessage); // read until new line meaning end of header while (!response.eof () && header != "\r") { std::getline (response, header); auto colon = header.find (':'); if (colon != std::string::npos) { std::string field = header.substr (0, colon); header.resize (header.length () - 1); // delete \r if (field == i2p::util::http::ETAG) m_Etag = header.substr (colon + 1); else if (field == i2p::util::http::LAST_MODIFIED) m_LastModified = header.substr (colon + 1); else if (field == i2p::util::http::TRANSFER_ENCODING) isChunked = !header.compare (colon + 1, std::string::npos, "chunked"); } } LogPrint (eLogInfo, m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified); if (!response.eof ()) { success = true; if (!isChunked) m_Book.LoadHostsFromStream (response); else { // merge chunks std::stringstream merged; i2p::util::http::MergeChunkedResponse (response, merged); m_Book.LoadHostsFromStream (merged); } } } else if (status == 304) { success = true; LogPrint (eLogInfo, "No updates from ", m_Link); } else LogPrint (eLogWarning, "Adressbook HTTP response ", status); } else
Server::Server(boost::asio::io_service &io_service, boost::asio::ip::udp::endpoint endpoint) :socket(io_service, endpoint) { AsyncReceive(); }