68 void RCONSession::disconnect() |
68 void RCONSession::disconnect() |
69 { |
69 { |
70 if (m_state > RCON_CONNECTING) |
70 if (m_state > RCON_CONNECTING) |
71 { |
71 { |
72 // Say goodbye to remote |
72 // Say goodbye to remote |
73 Bytestream packet; |
73 send({CLRC_DISCONNECT}); |
74 packet.write_byte(CLRC_DISCONNECT); |
|
75 this->send(packet); |
|
76 m_interface->disconnected(); |
74 m_interface->disconnected(); |
77 } |
75 } |
78 |
76 |
79 m_state = RCON_DISCONNECTED; |
77 m_state = RCON_DISCONNECTED; |
80 } |
78 } |
81 |
79 |
82 // ------------------------------------------------------------------------------------------------- |
80 // ------------------------------------------------------------------------------------------------- |
83 // |
81 // |
84 void RCONSession::send(const Bytestream& packet) |
82 void RCONSession::send(const Vector<unsigned char>& packet) |
85 { |
83 { |
86 m_socket.send(m_address, packet); |
84 m_socket.send(m_address, packet); |
87 } |
85 } |
88 |
86 |
89 // ------------------------------------------------------------------------------------------------- |
87 // ------------------------------------------------------------------------------------------------- |
124 void RCONSession::handlePacket(Datagram& datagram) |
120 void RCONSession::handlePacket(Datagram& datagram) |
125 { |
121 { |
126 if (datagram.address != m_address) |
122 if (datagram.address != m_address) |
127 return; |
123 return; |
128 |
124 |
|
125 Bytestream stream(datagram.message); |
|
126 |
129 try |
127 try |
130 { |
128 { |
131 while (datagram.message.bytes_left() > 0) |
129 while (stream.bytesLeft() > 0) |
132 { |
130 { |
133 int header = datagram.message.read_byte(); |
131 int header = stream.readByte(); |
134 |
132 |
135 switch (ServerResponse(header)) |
133 switch (ServerResponse(header)) |
136 { |
134 { |
137 case SVRC_OLDPROTOCOL: |
135 case SVRC_OLDPROTOCOL: |
138 m_interface->printError("Your RCON client is using outdated protocol.\n"); |
136 m_interface->printError("Your RCON client is using outdated protocol.\n"); |
155 m_state = RCON_DISCONNECTED; |
153 m_state = RCON_DISCONNECTED; |
156 break; |
154 break; |
157 |
155 |
158 case SVRC_MESSAGE: |
156 case SVRC_MESSAGE: |
159 { |
157 { |
160 String message = datagram.message.read_string(); |
158 String message = stream.readString(); |
161 message.normalize(); |
159 message.normalize(); |
162 m_interface->printText("%s\n", message.chars()); |
160 m_interface->printText("%s\n", message.chars()); |
163 } |
161 } |
164 break; |
162 break; |
165 |
163 |
166 case SVRC_LOGGEDIN: |
164 case SVRC_LOGGEDIN: |
167 m_interface->print("Login successful!\n"); |
165 m_interface->print("Login successful!\n"); |
168 m_serverProtocol = datagram.message.read_byte(); |
166 m_serverProtocol = stream.readByte(); |
169 m_hostname = datagram.message.read_string(); |
167 m_hostname = stream.readString(); |
170 m_interface->setTitle(m_hostname); |
168 m_interface->setTitle(m_hostname); |
171 m_state = RCON_CONNECTED; |
169 m_state = RCON_CONNECTED; |
172 |
170 |
173 for (int i = datagram.message.read_byte(); i > 0; --i) |
171 for (int i = stream.readByte(); i > 0; --i) |
174 processServerUpdates(datagram.message); |
172 processServerUpdates(stream); |
175 |
173 |
176 m_interface->print("Previous messages:\n"); |
174 m_interface->print("Previous messages:\n"); |
177 |
175 |
178 for (int i = datagram.message.read_byte(); i > 0; --i) |
176 for (int i = stream.readByte(); i > 0; --i) |
179 { |
177 { |
180 String message = datagram.message.read_string(); |
178 String message = stream.readString(); |
181 message.normalize(); |
179 message.normalize(); |
182 m_interface->printText("--- %s\n", message.chars()); |
180 m_interface->printText("--- %s\n", message.chars()); |
183 } |
181 } |
184 |
182 |
185 m_interface->print("End of previous messages.\n"); |
183 m_interface->print("End of previous messages.\n"); |
186 break; |
184 break; |
187 |
185 |
188 case SVRC_UPDATE: |
186 case SVRC_UPDATE: |
189 processServerUpdates(datagram.message); |
187 processServerUpdates(stream); |
190 break; |
188 break; |
191 |
189 |
192 case SVRC_TOOMANYTABCOMPLETES: |
190 case SVRC_TOOMANYTABCOMPLETES: |
193 { |
191 { |
194 unsigned int numCompletions = datagram.message.read_short(); |
192 unsigned int numCompletions = stream.readShort(); |
195 m_interface->print("%d completions for '%s'.\n", |
193 m_interface->print("%d completions for '%s'.\n", |
196 int(numCompletions), m_lastTabComplete.chars()); |
194 int(numCompletions), m_lastTabComplete.chars()); |
197 } |
195 } |
198 break; |
196 break; |
199 |
197 |
200 case SVRC_TABCOMPLETE: |
198 case SVRC_TABCOMPLETE: |
201 { |
199 { |
202 StringList completes; |
200 StringList completes; |
203 completes.resize(datagram.message.read_byte()); |
201 completes.resize(stream.readByte()); |
204 |
202 |
205 for (String& completion : completes) |
203 for (String& completion : completes) |
206 completion = datagram.message.read_string(); |
204 completion = stream.readString(); |
207 |
205 |
208 if (completes.size() == 1) |
206 if (completes.size() == 1) |
209 { |
207 { |
210 m_interface->tabComplete(m_lastTabComplete, completes[0]); |
208 m_interface->tabComplete(m_lastTabComplete, completes[0]); |
211 } |
209 } |
231 } |
229 } |
232 } |
230 } |
233 |
231 |
234 void RCONSession::processServerUpdates(Bytestream& packet) |
232 void RCONSession::processServerUpdates(Bytestream& packet) |
235 { |
233 { |
236 int header = packet.read_byte(); |
234 int header = packet.readByte(); |
237 |
235 |
238 switch (RCONUpdateType(header)) |
236 switch (RCONUpdateType(header)) |
239 { |
237 { |
240 case SVRCU_PLAYERDATA: |
238 case SVRCU_PLAYERDATA: |
241 { |
239 { |
242 StringList players; |
240 StringList players; |
243 |
241 |
244 for (int i = packet.read_byte(); i > 0; --i) |
242 for (int i = packet.readByte(); i > 0; --i) |
245 players.append(packet.read_string()); |
243 players.append(packet.readString()); |
246 |
244 |
247 m_interface->setPlayerNames(players); |
245 m_interface->setPlayerNames(players); |
248 } |
246 } |
249 break; |
247 break; |
250 |
248 |
251 case SVRCU_ADMINCOUNT: |
249 case SVRCU_ADMINCOUNT: |
252 m_adminCount = packet.read_byte(); |
250 m_adminCount = packet.readByte(); |
253 m_interface->updateStatusBar(); |
251 m_interface->updateStatusBar(); |
254 break; |
252 break; |
255 |
253 |
256 case SVRCU_MAP: |
254 case SVRCU_MAP: |
257 m_level = packet.read_string(); |
255 m_level = packet.readString(); |
258 m_interface->updateStatusBar(); |
256 m_interface->updateStatusBar(); |
259 break; |
257 break; |
260 |
258 |
261 default: |
259 default: |
262 m_interface->printWarning("Unknown server update type: %d\n", header); |
260 m_interface->printWarning("Unknown server update type: %d\n", header); |
274 // ------------------------------------------------------------------------------------------------- |
272 // ------------------------------------------------------------------------------------------------- |
275 // |
273 // |
276 void RCONSession::sendHello() |
274 void RCONSession::sendHello() |
277 { |
275 { |
278 m_interface->print("Connecting to %s...\n", m_address.to_string(IPAddress::WITH_PORT).chars()); |
276 m_interface->print("Connecting to %s...\n", m_address.to_string(IPAddress::WITH_PORT).chars()); |
279 Bytestream packet; |
277 send({CLRC_BEGINCONNECTION, RCON_PROTOCOL_VERSION}); |
280 packet.write_byte(CLRC_BEGINCONNECTION); |
|
281 packet.write_byte(RCON_PROTOCOL_VERSION); |
|
282 send(packet); |
|
283 bumpLastPing(); |
278 bumpLastPing(); |
284 } |
279 } |
285 |
280 |
286 // ------------------------------------------------------------------------------------------------- |
281 // ------------------------------------------------------------------------------------------------- |
287 // |
282 // |
288 void RCONSession::sendPassword() |
283 void RCONSession::sendPassword() |
289 { |
284 { |
290 m_interface->print("Authenticating...\n"); |
285 m_interface->print("Authenticating...\n"); |
291 Bytestream packet; |
286 Vector<unsigned char> message; |
292 packet.write_byte(CLRC_PASSWORD); |
287 Bytestream stream(message); |
293 packet.write_string((m_salt + m_password).md5()); |
288 stream.writeByte(CLRC_PASSWORD); |
294 send(packet); |
289 stream.writeString((m_salt + m_password).md5()); |
|
290 send(message); |
295 bumpLastPing(); |
291 bumpLastPing(); |
296 } |
292 } |
297 |
293 |
298 // ------------------------------------------------------------------------------------------------- |
294 // ------------------------------------------------------------------------------------------------- |
299 // |
295 // |
319 } |
315 } |
320 |
316 |
321 // ------------------------------------------------------------------------------------------------- |
317 // ------------------------------------------------------------------------------------------------- |
322 // Returns true if the message was successfully sent. |
318 // Returns true if the message was successfully sent. |
323 // |
319 // |
324 bool RCONSession::sendCommand(const String& message) |
320 bool RCONSession::sendCommand(const String& commandString) |
325 { |
321 { |
326 if (m_state != RCON_CONNECTED or message.isEmpty()) |
322 if (m_state != RCON_CONNECTED or commandString.isEmpty()) |
327 return false; |
323 return false; |
328 |
324 |
329 Bytestream packet; |
325 Vector<unsigned char> message; |
330 packet.write_byte(CLRC_COMMAND); |
326 Bytestream stream(message); |
331 packet.write_string(message); |
327 stream.writeByte(CLRC_COMMAND); |
332 send(packet); |
328 stream.writeString(commandString); |
|
329 send(message); |
333 bumpLastPing(); |
330 bumpLastPing(); |
334 return true; |
331 return true; |
335 } |
332 } |
336 |
333 |
337 // ------------------------------------------------------------------------------------------------- |
334 // ------------------------------------------------------------------------------------------------- |