1 /*
2 	This file is part of Warzone 2100.
3 	Copyright (C) 1999-2004  Eidos Interactive
4 	Copyright (C) 2005-2020  Warzone 2100 Project
5 
6 	Warzone 2100 is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 2 of the License, or
9 	(at your option) any later version.
10 
11 	Warzone 2100 is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 	GNU General Public License for more details.
15 
16 	You should have received a copy of the GNU General Public License
17 	along with Warzone 2100; if not, write to the Free Software
18 	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 // ////////////////////////////////////////////////////////////////////////
21 // Includes
22 #include "lib/framework/frame.h"
23 
24 #include <time.h>
25 #include <physfs.h>
26 #include "lib/framework/physfs_ext.h"
27 #include "lib/framework/wztime.h"
28 
29 #include "netlog.h"
30 #include "netplay.h"
31 
32 // ////////////////////////////////////////////////////////////////////////
33 // Logging for debug only
34 // ////////////////////////////////////////////////////////////////////////
35 
36 #define NUM_GAME_PACKETS 256
37 
38 static PHYSFS_file	*pFileHandle = nullptr;
39 static uint32_t		packetcount[2][NUM_GAME_PACKETS];
40 static uint32_t		packetsize[2][NUM_GAME_PACKETS];
41 
NETstartLogging(void)42 bool NETstartLogging(void)
43 {
44 	time_t aclock;
45 	char buf[256];
46 	static char filename[256] = {'\0'};
47 	int i;
48 
49 	for (i = 0; i < NUM_GAME_PACKETS; i++)
50 	{
51 		packetcount[0][i] = 0;
52 		packetsize[0][i] = 0;
53 		packetcount[1][i] = 0;
54 		packetsize[1][i] = 0;
55 	}
56 
57 	time(&aclock);                   /* Get time in seconds */
58 	auto newtime = getLocalTime(aclock);    /* Convert time to struct */
59 
60 	snprintf(filename, sizeof(filename), "logs/netplay-%04d%02d%02d_%02d%02d%02d.log", newtime.tm_year + 1900, newtime.tm_mon + 1, newtime.tm_mday, newtime.tm_hour, newtime.tm_min, newtime.tm_sec);
61 	pFileHandle = PHYSFS_openWrite(filename);   // open the file
62 	if (!pFileHandle)
63 	{
64 		debug(LOG_ERROR, "Could not create net log %s: %s", filename,
65 		      WZ_PHYSFS_getLastError());
66 		return false;
67 	}
68 	snprintf(buf, sizeof(buf), "NETPLAY log: %s\n", getAscTime(newtime).c_str());
69 	WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
70 	return true;
71 }
72 
NETstopLogging(void)73 bool NETstopLogging(void)
74 {
75 	static const char dash_line[] = "-----------------------------------------------------------\n";
76 	char buf[256];
77 	int i;
78 	UDWORD totalBytessent = 0, totalBytesrecv = 0, totalPacketsent = 0, totalPacketrecv = 0;
79 
80 	if (!pFileHandle)
81 	{
82 		return false;
83 	}
84 
85 	/* Output stats */
86 	for (i = 0; i < NUM_GAME_PACKETS; i++)
87 	{
88 		if (!strcmp(messageTypeToString(i), "(UNUSED)"))
89 		{
90 			continue;
91 		}
92 		else
93 		{
94 			snprintf(buf, sizeof(buf), "%-24s:\t received %u times, %u bytes; sent %u times, %u bytes\n", messageTypeToString(i),
95 			         packetcount[1][i], packetsize[1][i], packetcount[0][i], packetsize[0][i]);
96 		}
97 		WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
98 		totalBytessent += packetsize[0][i];
99 		totalBytesrecv += packetsize[1][i];
100 		totalPacketsent += packetcount[0][i];
101 		totalPacketrecv += packetcount[1][i];
102 	}
103 	snprintf(buf, sizeof(buf), "== Total bytes sent %u, Total bytes received %u ==\n", totalBytessent, totalBytesrecv);
104 	WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
105 	snprintf(buf, sizeof(buf), "== Total packets sent %u, recv %u ==\n", totalPacketsent, totalPacketrecv);
106 	WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
107 	snprintf(buf, sizeof(buf), "\n-Sync statistics -\n");
108 	WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
109 	WZ_PHYSFS_writeBytes(pFileHandle, dash_line, static_cast<PHYSFS_uint32>(strlen(dash_line)));
110 	snprintf(buf, sizeof(buf), "joins: %u, kicks: %u, drops: %u, left %u\n", sync_counter.joins, sync_counter.kicks, sync_counter.drops, sync_counter.left);
111 	WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
112 	snprintf(buf, sizeof(buf), "banned: %u, cantjoin: %u, rejected: %u\n", sync_counter.banned, sync_counter.cantjoin, sync_counter.rejected);
113 	WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
114 	if (sync_counter.banned && IPlist)
115 	{
116 		snprintf(buf, sizeof(buf), "Banned list:\n");
117 		WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
118 		for (i = 0; i < MAX_BANS; i++)
119 		{
120 			if (IPlist[i].IPAddress[0] != '\0')
121 			{
122 				snprintf(buf, sizeof(buf), "player %s, IP: %s\n", IPlist[i].pname, IPlist[i].IPAddress);
123 				WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
124 			}
125 		}
126 
127 	}
128 	WZ_PHYSFS_writeBytes(pFileHandle, dash_line, static_cast<PHYSFS_uint32>(strlen(dash_line)));
129 	WZ_PHYSFS_writeBytes(pFileHandle, dash_line, static_cast<PHYSFS_uint32>(strlen(dash_line)));
130 
131 	if (!PHYSFS_close(pFileHandle))
132 	{
133 		debug(LOG_ERROR, "Could not close net log: %s", WZ_PHYSFS_getLastError());
134 		return false;
135 	}
136 	pFileHandle = nullptr;
137 
138 	return true;
139 }
140 
141 /** log packet
142  *  \param type, uint8_t, the packet's type.
143  *  \param size, uint32_t, the packet's size
144  *  \param received, bool, true if we are receiving a packet, false if we are sending a packet.
145 */
NETlogPacket(uint8_t type,uint32_t size,bool received)146 void NETlogPacket(uint8_t type, uint32_t size, bool received)
147 {
148 	STATIC_ASSERT((1 << (8 * sizeof(type))) == NUM_GAME_PACKETS); // NUM_GAME_PACKETS must be larger than maximum possible type.
149 	packetcount[received][type]++;
150 	packetsize[received][type] += size;
151 }
152 
NETlogEntry(const char * str,UDWORD a,UDWORD b)153 bool NETlogEntry(const char *str, UDWORD a, UDWORD b)
154 {
155 	static const char star_line[] = "************************************************************\n";
156 	static UDWORD lastframe = 0;
157 	UDWORD frame = frameGetFrameNumber();
158 	time_t aclock;
159 	char buf[256];
160 
161 	if (!pFileHandle)
162 	{
163 		return false;
164 	}
165 
166 	time(&aclock);					/* Get time in seconds */
167 	auto newtime_result = getLocalTimeOpt(aclock);		/* Convert time to struct */
168 
169 	if (!newtime_result.has_value() || !pFileHandle)
170 	{
171 		debug(LOG_ERROR, "Fatal error averted in NETlog");
172 		return false;
173 	}
174 
175 	struct tm newtime = newtime_result.value();
176 
177 	// check to see if a new frame.
178 	if (frame != lastframe)
179 	{
180 		static const char dash_line[] = "-----------------------------------------------------------\n";
181 
182 		lastframe = frame;
183 		WZ_PHYSFS_writeBytes(pFileHandle, dash_line, static_cast<PHYSFS_uint32>(strlen(dash_line)));
184 	}
185 
186 	if (a < NUM_GAME_PACKETS)
187 		// replace common msgs with txt descriptions
188 	{
189 		snprintf(buf, sizeof(buf), "%s \t: %s \t:%d\t\t%s", str, messageTypeToString(a), b, getAscTime(newtime).c_str());
190 	}
191 	else if (a == SYNC_FLAG)
192 	{
193 		snprintf(buf, sizeof(buf), "%s \t: %d \t(Sync) \t%s", str, b, getAscTime(newtime).c_str());
194 	}
195 	else
196 	{
197 		snprintf(buf, sizeof(buf), "%s \t:%d \t\t\t:%d\t\t%s", str, a, b, getAscTime(newtime).c_str());
198 	}
199 
200 	if (a == NET_PLAYER_LEAVING || a == NET_PLAYER_DROPPED)
201 	{
202 		// Write a starry line above NET_LEAVING messages
203 		WZ_PHYSFS_writeBytes(pFileHandle, star_line, static_cast<PHYSFS_uint32>(strlen(star_line)));
204 		WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
205 		WZ_PHYSFS_writeBytes(pFileHandle, star_line, static_cast<PHYSFS_uint32>(strlen(star_line)));
206 	}
207 	else
208 	{
209 		WZ_PHYSFS_writeBytes(pFileHandle, buf, static_cast<PHYSFS_uint32>(strlen(buf)));
210 	}
211 
212 	PHYSFS_flush(pFileHandle);
213 	return true;
214 }
215