aboutsummaryrefslogtreecommitdiff
path: root/src/client/filecache.cpp
blob: 46bbe40595edab8107e9030e8f16853554e204bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2013 Jonathan Neuschäfer <j.neuschaefer@gmx.net>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "filecache.h"

#include "network/networkprotocol.h"
#include "log.h"
#include "filesys.h"
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>

bool FileCache::loadByPath(const std::string &path, std::ostream &os)
{
	std::ifstream fis(path.c_str(), std::ios_base::binary);

	if(!fis.good()){
		verbosestream<<"FileCache: File not found in cache: "
				<<path<<std::endl;
		return false;
	}

	bool bad = false;
	for(;;){
		char buf[1024];
		fis.read(buf, 1024);
		std::streamsize len = fis.gcount();
		os.write(buf, len);
		if(fis.eof())
			break;
		if(!fis.good()){
			bad = true;
			break;
		}
	}
	if(bad){
		errorstream<<"FileCache: Failed to read file from cache: \""
				<<path<<"\""<<std::endl;
	}

	return !bad;
}

bool FileCache::updateByPath(const std::string &path, const std::string &data)
{
	std::ofstream file(path.c_str(), std::ios_base::binary |
			std::ios_base::trunc);

	if(!file.good())
	{
		errorstream<<"FileCache: Can't write to file at "
				<<path<<std::endl;
		return false;
	}

	file.write(data.c_str(), data.length());
	file.close();

	return !file.fail();
}

bool FileCache::update(const std::string &name, const std::string &data)
{
	std::string path = m_dir + DIR_DELIM + name;
	return updateByPath(path, data);
}

bool FileCache::load(const std::string &name, std::ostream &os)
{
	std::string path = m_dir + DIR_DELIM + name;
	return loadByPath(path, os);
}

bool FileCache::exists(const std::string &name)
{
	std::string path = m_dir + DIR_DELIM + name;
	std::ifstream fis(path.c_str(), std::ios_base::binary);
	return fis.good();
}
"hl ppc">#include "constants.h" #include "debug.h" #include "settings.h" #include "log.h" #ifdef _WIN32 // Without this some of the network functions are not found on mingw #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #define LAST_SOCKET_ERR() WSAGetLastError() typedef SOCKET socket_t; typedef int socklen_t; #else #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <fcntl.h> #include <netdb.h> #include <unistd.h> #include <arpa/inet.h> #define LAST_SOCKET_ERR() (errno) typedef int socket_t; #endif // Set to true to enable verbose debug output bool socket_enable_debug_output = false; // yuck static bool g_sockets_initialized = false; // Initialize sockets void sockets_init() { #ifdef _WIN32 // Windows needs sockets to be initialized before use WSADATA WsaData; if (WSAStartup(MAKEWORD(2, 2), &WsaData) != NO_ERROR) throw SocketException("WSAStartup failed"); #endif g_sockets_initialized = true; } void sockets_cleanup() { #ifdef _WIN32 // On Windows, cleanup sockets after use WSACleanup(); #endif } /* UDPSocket */ UDPSocket::UDPSocket(bool ipv6) { init(ipv6, false); } bool UDPSocket::init(bool ipv6, bool noExceptions) { if (!g_sockets_initialized) { dstream << "Sockets not initialized" << std::endl; return false; } // Use IPv6 if specified m_addr_family = ipv6 ? AF_INET6 : AF_INET; m_handle = socket(m_addr_family, SOCK_DGRAM, IPPROTO_UDP); if (socket_enable_debug_output) { dstream << "UDPSocket(" << (int)m_handle << ")::UDPSocket(): ipv6 = " << (ipv6 ? "true" : "false") << std::endl; } if (m_handle <= 0) { if (noExceptions) { return false; } throw SocketException(std::string("Failed to create socket: error ") + itos(LAST_SOCKET_ERR())); } setTimeoutMs(0); if (m_addr_family == AF_INET6) { // Allow our socket to accept both IPv4 and IPv6 connections // required on Windows: // https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx int value = 0; setsockopt(m_handle, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&value), sizeof(value)); } return true; } UDPSocket::~UDPSocket() { if (socket_enable_debug_output) { dstream << "UDPSocket( " << (int)m_handle << ")::~UDPSocket()" << std::endl; } #ifdef _WIN32 closesocket(m_handle); #else close(m_handle); #endif } void UDPSocket::Bind(Address addr) { if (socket_enable_debug_output) { dstream << "UDPSocket(" << (int)m_handle << ")::Bind(): " << addr.serializeString() << ":" << addr.getPort() << std::endl; } if (addr.getFamily() != m_addr_family) { static const char *errmsg = "Socket and bind address families do not match"; errorstream << "Bind failed: " << errmsg << std::endl; throw SocketException(errmsg); } if (m_addr_family == AF_INET6) { struct sockaddr_in6 address; memset(&address, 0, sizeof(address)); address = addr.getAddress6(); address.sin6_family = AF_INET6; address.sin6_port = htons(addr.getPort()); if (bind(m_handle, (const struct sockaddr *)&address, sizeof(struct sockaddr_in6)) < 0) { dstream << (int)m_handle << ": Bind failed: " << strerror(errno) << std::endl; throw SocketException("Failed to bind socket"); } } else { struct sockaddr_in address; memset(&address, 0, sizeof(address)); address = addr.getAddress(); address.sin_family = AF_INET; address.sin_port = htons(addr.getPort()); if (bind(m_handle, (const struct sockaddr *)&address, sizeof(struct sockaddr_in)) < 0) { dstream << (int)m_handle << ": Bind failed: " << strerror(errno) << std::endl; throw SocketException("Failed to bind socket"); } } } void UDPSocket::Send(const Address &destination, const void *data, int size) { bool dumping_packet = false; // for INTERNET_SIMULATOR if (INTERNET_SIMULATOR) dumping_packet = myrand() % INTERNET_SIMULATOR_PACKET_LOSS == 0; if (socket_enable_debug_output) { // Print packet destination and size dstream << (int)m_handle << " -> "; destination.print(&dstream); dstream << ", size=" << size; // Print packet contents dstream << ", data="; for (int i = 0; i < size && i < 20; i++) { if (i % 2 == 0) dstream << " "; unsigned int a = ((const unsigned char *)data)[i]; dstream << std::hex << std::setw(2) << std::setfill('0') << a; } if (size > 20) dstream << "..."; if (dumping_packet) dstream << " (DUMPED BY INTERNET_SIMULATOR)"; dstream << std::endl; } if (dumping_packet) { // Lol let's forget it dstream << "UDPSocket::Send(): INTERNET_SIMULATOR: dumping packet." << std::endl; return; } if (destination.getFamily() != m_addr_family) throw SendFailedException("Address family mismatch"); int sent; if (m_addr_family == AF_INET6) { struct sockaddr_in6 address = destination.getAddress6(); address.sin6_port = htons(destination.getPort()); sent = sendto(m_handle, (const char *)data, size, 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in6)); } else { struct sockaddr_in address = destination.getAddress(); address.sin_port = htons(destination.getPort()); sent = sendto(m_handle, (const char *)data, size, 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); } if (sent != size) throw SendFailedException("Failed to send packet"); } int UDPSocket::Receive(Address &sender, void *data, int size) { // Return on timeout if (!WaitData(m_timeout_ms)) return -1; int received; if (m_addr_family == AF_INET6) { struct sockaddr_in6 address; memset(&address, 0, sizeof(address)); socklen_t address_len = sizeof(address); received = recvfrom(m_handle, (char *)data, size, 0, (struct sockaddr *)&address, &address_len); if (received < 0) return -1; u16 address_port = ntohs(address.sin6_port); IPv6AddressBytes bytes; memcpy(bytes.bytes, address.sin6_addr.s6_addr, 16); sender = Address(&bytes, address_port); } else { struct sockaddr_in address; memset(&address, 0, sizeof(address)); socklen_t address_len = sizeof(address);