1 /*************************************************************************/
2 /*  file_access_network.h                                                */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #ifndef FILE_ACCESS_NETWORK_H
32 #define FILE_ACCESS_NETWORK_H
33 
34 #include "core/io/stream_peer_tcp.h"
35 #include "core/os/file_access.h"
36 #include "core/os/semaphore.h"
37 #include "core/os/thread.h"
38 
39 class FileAccessNetwork;
40 
41 class FileAccessNetworkClient {
42 
43 	struct BlockRequest {
44 
45 		int id;
46 		uint64_t offset;
47 		int size;
48 	};
49 
50 	List<BlockRequest> block_requests;
51 
52 	Semaphore *sem;
53 	Thread *thread;
54 	bool quit;
55 	Mutex *mutex;
56 	Mutex *blockrequest_mutex;
57 	Map<int, FileAccessNetwork *> accesses;
58 	Ref<StreamPeerTCP> client;
59 	int last_id;
60 
61 	Vector<uint8_t> block;
62 
63 	void _thread_func();
64 	static void _thread_func(void *s);
65 
66 	void put_32(int p_32);
67 	void put_64(int64_t p_64);
68 	int get_32();
69 	int64_t get_64();
70 	int lockcount;
71 	void lock_mutex();
72 	void unlock_mutex();
73 
74 	friend class FileAccessNetwork;
75 	static FileAccessNetworkClient *singleton;
76 
77 public:
get_singleton()78 	static FileAccessNetworkClient *get_singleton() { return singleton; }
79 
80 	Error connect(const String &p_host, int p_port, const String &p_password = "");
81 
82 	FileAccessNetworkClient();
83 	~FileAccessNetworkClient();
84 };
85 
86 class FileAccessNetwork : public FileAccess {
87 
88 	Semaphore *sem;
89 	Semaphore *page_sem;
90 	Mutex *buffer_mutex;
91 	bool opened;
92 	size_t total_size;
93 	mutable size_t pos;
94 	int id;
95 	mutable bool eof_flag;
96 	mutable int last_page;
97 	mutable uint8_t *last_page_buff;
98 
99 	int page_size;
100 	int read_ahead;
101 
102 	mutable int waiting_on_page;
103 	mutable int last_activity_val;
104 	struct Page {
105 		int activity;
106 		bool queued;
107 		Vector<uint8_t> buffer;
PagePage108 		Page() {
109 			activity = 0;
110 			queued = false;
111 		}
112 	};
113 
114 	mutable Vector<Page> pages;
115 
116 	mutable Error response;
117 
118 	uint64_t exists_modtime;
119 	friend class FileAccessNetworkClient;
120 	void _queue_page(int p_page) const;
121 	void _respond(size_t p_len, Error p_status);
122 	void _set_block(int p_offset, const Vector<uint8_t> &p_block);
123 
124 public:
125 	enum Command {
126 		COMMAND_OPEN_FILE,
127 		COMMAND_READ_BLOCK,
128 		COMMAND_CLOSE,
129 		COMMAND_FILE_EXISTS,
130 		COMMAND_GET_MODTIME,
131 	};
132 
133 	enum Response {
134 		RESPONSE_OPEN,
135 		RESPONSE_DATA,
136 		RESPONSE_FILE_EXISTS,
137 		RESPONSE_GET_MODTIME,
138 	};
139 
140 	virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
141 	virtual void close(); ///< close a file
142 	virtual bool is_open() const; ///< true when file is open
143 
144 	virtual void seek(size_t p_position); ///< seek to a given position
145 	virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
146 	virtual size_t get_position() const; ///< get position in the file
147 	virtual size_t get_len() const; ///< get size of the file
148 
149 	virtual bool eof_reached() const; ///< reading passed EOF
150 
151 	virtual uint8_t get_8() const; ///< get a byte
152 	virtual int get_buffer(uint8_t *p_dst, int p_length) const;
153 
154 	virtual Error get_error() const; ///< get last error
155 
156 	virtual void flush();
157 	virtual void store_8(uint8_t p_dest); ///< store a byte
158 
159 	virtual bool file_exists(const String &p_path); ///< return true if a file exists
160 
161 	virtual uint64_t _get_modified_time(const String &p_file);
162 	virtual uint32_t _get_unix_permissions(const String &p_file);
163 	virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
164 
165 	static void configure();
166 
167 	FileAccessNetwork();
168 	~FileAccessNetwork();
169 };
170 
171 #endif // FILE_ACCESS_NETWORK_H
172