| 31 #include <time.h> |
31 #include <time.h> |
| 32 #include "rconsession.h" |
32 #include "rconsession.h" |
| 33 #include "../interface.h" |
33 #include "../interface.h" |
| 34 BEGIN_ZFC_NAMESPACE |
34 BEGIN_ZFC_NAMESPACE |
| 35 |
35 |
| |
36 struct PacketHeader |
| |
37 { |
| |
38 int32_t header; |
| |
39 int sequenceNumber; |
| |
40 }; |
| |
41 |
| 36 // ------------------------------------------------------------------------------------------------- |
42 // ------------------------------------------------------------------------------------------------- |
| 37 // |
43 // |
| 38 RCONSession::RCONSession() : |
44 RCONSession::RCONSession() : |
| 39 m_state(RCON_DISCONNECTED), |
45 m_state(RCON_DISCONNECTED), |
| 40 m_lastPing(0), |
46 m_lastPing(0), |
| 41 m_adminCount(0), |
47 m_adminCount(0), |
| |
48 m_lastMissingPacketRequest(0), |
| 42 m_interface(nullptr) |
49 m_interface(nullptr) |
| 43 { |
50 { |
| 44 if (not m_socket.set_blocking(false)) |
51 if (not m_socket.set_blocking(false)) |
| 45 { |
52 { |
| 46 fprintf(stderr, "unable to set socket as non-blocking: %s\n", |
53 fprintf(stderr, "unable to set socket as non-blocking: %s\n", |
| 109 send({CLRC_PONG}); |
116 send({CLRC_PONG}); |
| 110 bumpLastPing(); |
117 bumpLastPing(); |
| 111 } |
118 } |
| 112 } |
119 } |
| 113 |
120 |
| |
121 // Check for new packets in our socket |
| 114 for (Datagram datagram; m_socket.read(datagram);) |
122 for (Datagram datagram; m_socket.read(datagram);) |
| 115 handlePacket(datagram); |
123 { |
| 116 } |
124 // Packet came from the wrong address, ignore |
| 117 |
125 if (datagram.address != m_address) |
| 118 // ------------------------------------------------------------------------------------------------- |
126 continue; |
| 119 // |
127 |
| 120 void RCONSession::handlePacket(Datagram& datagram) |
128 // Parse and cut off the header. |
| 121 { |
129 PacketHeader header; |
| 122 if (datagram.address != m_address) |
130 { |
| 123 return; |
131 // Read the header, and find the sequence number |
| 124 |
132 Bytestream stream(datagram.message); |
| 125 Bytestream stream(datagram.message); |
133 header.header = stream.readLong(); |
| |
134 header.sequenceNumber = (header.header != 0) ? stream.readLong() : -1; |
| |
135 datagram.message = datagram.message.splice(stream.position(), datagram.message.size()); |
| |
136 } |
| |
137 |
| |
138 // Try to store this packet into the queue. However, do not try to store packets without a sequence number. |
| |
139 bool stored = false; |
| |
140 |
| |
141 if (header.sequenceNumber != -1) |
| |
142 stored = m_packetQueue.addPacket(header.sequenceNumber, datagram.message); |
| |
143 |
| |
144 // If the packet was not stored, we are to just process it right away. |
| |
145 if (stored == false) |
| |
146 handlePacket(datagram.message); |
| |
147 } |
| |
148 |
| |
149 // Check if we can now also process some packets from the queue. |
| |
150 if (m_packetQueue.hasPacketsToPop()) |
| |
151 { |
| |
152 ByteArray message; |
| |
153 while (m_packetQueue.popNextPacket(message)) |
| |
154 handlePacket(message); |
| |
155 } |
| |
156 |
| |
157 // Check whether there are packets stuck in the queue. If this is the case, we have lost some packets and need to |
| |
158 // ask the game server to re-send them. |
| |
159 if (m_packetQueue.isStuck() and m_lastMissingPacketRequest + 1 < time(NULL)) |
| |
160 { |
| |
161 m_interface->printWarning("Missing packets detected. Packets currently in queue:\n"); |
| |
162 |
| |
163 for (int packetNumber : m_packetQueue.getWaitingPackets()) |
| |
164 m_interface->printWarning("- %d:\n", packetNumber); |
| |
165 |
| |
166 m_lastMissingPacketRequest = time(NULL); |
| |
167 ByteArray message; |
| |
168 Bytestream stream(message); |
| |
169 stream.writeByte(CLRC_MISSINGPACKET); |
| |
170 |
| |
171 for (int packetNumber : m_packetQueue.getLostPackets()) |
| |
172 { |
| |
173 m_interface->printWarning("Requesting lost packet %d\n", packetNumber); |
| |
174 stream.writeLong(packetNumber); |
| |
175 } |
| |
176 |
| |
177 send(message); |
| |
178 } |
| |
179 } |
| |
180 |
| |
181 // ------------------------------------------------------------------------------------------------- |
| |
182 // |
| |
183 void RCONSession::handlePacket(ByteArray& message) |
| |
184 { |
| |
185 Bytestream stream(message); |
| 126 |
186 |
| 127 try |
187 try |
| 128 { |
188 { |
| 129 int32_t header = stream.readLong(); |
|
| 130 int32_t sequenceNumber = (header != 0) ? stream.readLong() : 0; |
|
| 131 m_interface->print("Recieved packet with header 0x%x and sequence number #%d\n", header, sequenceNumber); |
|
| 132 |
|
| 133 while (stream.bytesLeft() > 0) |
189 while (stream.bytesLeft() > 0) |
| 134 { |
190 { |
| 135 int header = stream.readByte(); |
191 int header = stream.readByte(); |
| 136 |
192 |
| 137 switch (ServerResponse(header)) |
193 switch (ServerResponse(header)) |