campaignd: WIP: implement sending add-ons on Windows
Does not work fully yet because for whatever reason the client believes that the add-on is 3,7 gigabytes large (and, thus, the download doesn't end, as campaignd sends signiticantly less than that).
This commit is contained in:
parent
168e514144
commit
09edad8ad9
1 changed files with 100 additions and 0 deletions
|
@ -23,10 +23,16 @@
|
|||
#include <sys/sendfile.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "server_base.hpp"
|
||||
#include "simple_wml.hpp"
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
template<typename Handler, typename ErrorHandler>
|
||||
struct handle_doc
|
||||
{
|
||||
|
@ -161,6 +167,100 @@ void async_send_file(socket_ptr socket, const std::string& filename, Handler han
|
|||
async_write(*socket, buffers, op);
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
template<typename Handler, typename ErrorHandler>
|
||||
struct sendfile_op
|
||||
{
|
||||
socket_ptr sock_;
|
||||
HANDLE file_;
|
||||
OVERLAPPED overlap_;
|
||||
Handler handler_;
|
||||
ErrorHandler error_handler_;
|
||||
bool pending_;
|
||||
|
||||
void operator()(boost::system::error_code ec, std::size_t)
|
||||
{
|
||||
bool failed = false;
|
||||
if (!pending_)
|
||||
{
|
||||
BOOL success = TransmitFile(sock_->native_handle(), file_, 0, 0, &overlap_, nullptr, 0);
|
||||
if (!success)
|
||||
{
|
||||
int winsock_ec = WSAGetLastError();
|
||||
if (winsock_ec == WSA_IO_PENDING || winsock_ec == ERROR_IO_PENDING)
|
||||
{
|
||||
// The request is pending. Wait until it completes.
|
||||
pending_ = true;
|
||||
sock_->async_write_some(boost::asio::null_buffers(), *this);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD win_ec = GetLastError();
|
||||
if (win_ec != ERROR_IO_PENDING && win_ec != ERROR_SUCCESS)
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
else if (!HasOverlappedIoCompleted(&overlap_))
|
||||
{
|
||||
// Keep waiting.
|
||||
sock_->async_write_some(boost::asio::null_buffers(), *this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(file_);
|
||||
CloseHandle(overlap_.hEvent);
|
||||
|
||||
if (!failed)
|
||||
{
|
||||
handler_(sock_);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_handler_(sock_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Handler, typename ErrorHandler>
|
||||
void async_send_file(socket_ptr socket, const std::string& filename, Handler handler, ErrorHandler error_handler)
|
||||
{
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
size_t filesize = filesystem::file_size(filename);
|
||||
std::wstring filename_ucs2 = unicode_cast<std::wstring>(filename);
|
||||
HANDLE in_file = CreateFileW(filename_ucs2.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
|
||||
if (GetLastError() != ERROR_SUCCESS)
|
||||
{
|
||||
throw std::runtime_error("Failed to open the file");
|
||||
}
|
||||
|
||||
sendfile_op<Handler, ErrorHandler> op = { socket, in_file, OVERLAPPED(), handler, error_handler, false };
|
||||
|
||||
HANDLE event = CreateEvent(nullptr, TRUE, TRUE, nullptr);
|
||||
if (GetLastError() != ERROR_SUCCESS)
|
||||
{
|
||||
throw std::runtime_error("Failed to create an event");
|
||||
}
|
||||
|
||||
op.overlap_.hEvent = event;
|
||||
|
||||
handle_doc<Handler, ErrorHandler> handle_send_doc(socket, handler, error_handler, filesize, nullptr);
|
||||
buffers.push_back(boost::asio::buffer(handle_send_doc.data_size->buf, 4));
|
||||
async_write(*socket, buffers, op);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// TODO: Implement this for systems without sendfile()
|
||||
|
|
Loading…
Add table
Reference in a new issue