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