Skip to content

Commit b5bec02

Browse files
author
yorickvanpelt
committed
- Cleanup: remove some error handling, because returning invalid data also makes it crash somewhere else, so it had no use
- Add: support for connectionless udp
1 parent ac1e247 commit b5bec02

File tree

2 files changed

+92
-102
lines changed

2 files changed

+92
-102
lines changed

openttd/client.py

+67-81
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from log import LOG
1818
import constants as const
1919
from datastorageclass import DataStorageClass
20+
import _error
2021

2122
#connection modes
2223
M_NONE = 0
@@ -94,53 +95,41 @@ def __init__(self, ip, port, debugLevel=0, uid=None):
9495
self.running = True # sighandler will change this value
9596
self.lock = threading.Lock()
9697
threading.Thread.__init__(self)
98+
def createsocket(self, mode=M_BOTH):
99+
if mode & M_TCP:
100+
self.socket_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
101+
self.socket_tcp.settimeout(5)
102+
if mode & M_UDP:
103+
self.socket_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
104+
self.socket_udp.settimeout(5)
97105

98106
def connect(self, mode=M_BOTH):
107+
self.createsocket(mode)
108+
99109
try:
100-
LOG.debug('creating sockets')
101-
102-
if mode & M_TCP:
103-
self.socket_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
104-
self.socket_tcp.settimeout(5)
105-
if mode & M_UDP:
106-
self.socket_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
107-
self.socket_udp.settimeout(5)
108-
109-
try:
110-
self.ip = socket.gethostbyname(self.ip)
111-
except Exception, e:
112-
LOG.error('gethost error on ip %s: %s'%(str(self.ip), str(e)))
113-
if not str(e) in self.errors:
114-
self.errors.append(str(e))
115-
return False
116-
117-
LOG.debug("connecting to %s:%d" % (self.ip, self.port))
118-
119-
if mode & M_TCP:
120-
self.socket_tcp.connect((self.ip, self.port))
121-
if mode & M_UDP:
122-
self.socket_udp.connect((self.ip, self.port))
123-
124-
self.connectionmode |= mode
125-
self.running = True
126-
#self.getGameInfo()
127-
128-
#self.throwRandomData()
129-
#self.packetTest()
130-
#self.sendMsg_UDP(const.PACKET_UDP_CLIENT_FIND_SERVER)
131-
#self.sendRaw(self.packetTest())
132-
#data=self.receiveMsg_UDP()
110+
self.ip = socket.gethostbyname(self.ip)
111+
except Exception, e:
112+
raise _error.ConnectionError("problem resolving host %s: %s" % (str(self.ip), str(e)))
133113

134-
LOG.debug( "connect finished" )
135-
return True
136-
except socket.error, e:
137-
LOG.error('connect error: %d (%s)' % (e[0], e[1]))
138-
errorMsg = StringIO.StringIO()
139-
traceback.print_exc(file=errorMsg)
140-
LOG.error(errorMsg.getvalue())
141-
if not str(e) in self.errors:
142-
self.errors.append(str(e))
143-
return False
114+
LOG.debug("connecting to %s:%d" % (self.ip, self.port))
115+
116+
if mode & M_TCP:
117+
self.socket_tcp.connect((self.ip, self.port))
118+
if mode & M_UDP:
119+
self.socket_udp.connect((self.ip, self.port))
120+
121+
self.connectionmode |= mode
122+
self.running = True
123+
#self.getGameInfo()
124+
125+
#self.throwRandomData()
126+
#self.packetTest()
127+
#self.sendMsg_UDP(const.PACKET_UDP_CLIENT_FIND_SERVER)
128+
#self.sendRaw(self.packetTest())
129+
#data=self.receiveMsg_UDP()
130+
131+
LOG.debug( "connect finished" )
132+
return True
144133
def disconnect(self, mode=M_BOTH):
145134
if not self.socket_tcp is None and mode & M_TCP:
146135
LOG.debug('closing TCP socket')
@@ -175,8 +164,7 @@ def getServerList(self):
175164
LOG.debug(" %s:%d" % (ip, port))
176165
return servers
177166
else:
178-
LOG.debug("got unknown protocol version in response from master server %d" % protocol_version)
179-
return None
167+
raise _error.WrongVersion("master server list request", protocol_version, const.NETWORK_MASTER_SERVER_VERSION)
180168

181169

182170
def getGRFInfo(self, grfs):
@@ -203,7 +191,7 @@ def getGRFInfo(self, grfs):
203191

204192
return newgrfs
205193
else:
206-
LOG.error("unexpected reply on const.PACKET_UDP_CLIENT_GET_NEWGRFS: %d" % (p.command))
194+
raise _error.UnexpectedResponse("PACKET_UDP_CLIENT_GET_NEWGRFS", str(p.command))
207195

208196
def getCompanyInfo(self):
209197
self.sendMsg_UDP(const.PACKET_UDP_CLIENT_DETAIL_INFO)
@@ -262,9 +250,9 @@ def getCompanyInfo(self):
262250
ret.spectators = players
263251
return ret
264252
else:
265-
LOG.error("unsupported NETWORK_COMPANY_INFO_VERSION: %d. supported version: %d" % (info_version, const.NETWORK_COMPANY_INFO_VERSION))
253+
raise _error.WrongVersion("PACKET_UDP_CLIENT_DETAIL_INFO", info_version, const.NETWORK_COMPANY_INFO_VERSION)
266254
else:
267-
LOG.error("unexpected reply on const.PACKET_UDP_CLIENT_DETAIL_INFO: %d" % (command))
255+
raise _error.UnexpectedResponse("PACKET_UDP_CLIENT_DETAIL_INFO", str(command))
268256
def getTCPCompanyInfo(self):
269257
self.sendMsg_TCP(const.PACKET_CLIENT_COMPANY_INFO)
270258
p = self.receiveMsg_TCP(True)
@@ -281,8 +269,7 @@ def getTCPCompanyInfo(self):
281269
if p is None:
282270
return None
283271
if p.command != const.PACKET_SERVER_COMPANY_INFO:
284-
LOG.error("unexpectged reply on const.PACKET_CLIENT_COMPANY_INFO: %d" % p.command)
285-
return None
272+
raise _error.UnexpectedResponse("PACKET_CLIENT_COMPANY_INFO", str(p.command))
286273
[info_version, player_count] = p.recv_something('BB')
287274
firsttime = False
288275

@@ -301,9 +288,9 @@ def getTCPCompanyInfo(self):
301288
companies.append(company)
302289
return companies
303290
else:
304-
LOG.error("unknown company info version %d, supported: %d" % (info_version, const.NETWORK_COMPANY_INFO_VERSION))
291+
raise _error.WrongVersion("PACKET_CLIENT_COMPANY_INFO", info_version, const.NETWORK_COMPANY_INFO_VERSION)
305292
else:
306-
LOG.error("unexpected reply on const.PACKET_CLIENT_COMPANY_INFO: %d" % (command))
293+
raise _error.UnexpectedResponse("PACKET_CLIENT_COMPANY_INFO", str(command))
307294

308295
def getGameInfo(self, encode_grfs=False, short=False):
309296
self.sendMsg_UDP(const.PACKET_UDP_CLIENT_FIND_SERVER)
@@ -379,25 +366,25 @@ def throwRandomData(self):
379366

380367

381368

382-
def sendRaw(self, data, type=M_NONE):
369+
def sendRaw(self, data, type, addr=None):
383370
if type == M_TCP:
384371
s = self.socket_tcp
385372
socketname = "TCP" # for errors
373+
useaddr = False
386374
elif type == M_UDP:
387375
s = self.socket_udp
388376
socketname = "UDP" # for errors
377+
useaddr = True
389378
else:
390-
LOG.error("cannot send: unknown type")
391-
return False
379+
return
392380
if s is None:
393381
# not connected
394-
LOG.error("cannot send: " + socketname + " not connected!")
395-
return False
396-
try:
382+
raise _error.ConnectionError("cannot send: " + socketname + " not connected!")
383+
if not addr is None and useaddr:
384+
s.sendto(data, address=addr)
385+
else:
397386
# send the data
398387
s.send(data)
399-
except socket.error, e:
400-
LOG.error("send error: %d (%s)" % (e[0], e[1]))
401388
return True
402389

403390

@@ -439,32 +426,32 @@ def receive_bytes(self, socket, bytes):
439426
data += socket.recv(bytes - len(data))
440427
readcounter += 1
441428
return data, readcounter
442-
def receiveMsg_UDP(self, datapacket = False):
443-
try:
444-
if self.socket_udp is None:
445-
return None
429+
def receiveMsg_UDP(self, datapacket = False, useaddr = False):
430+
if self.socket_udp is None:
431+
raise _error.ConnectionError("no udp socket for receiving")
432+
if useaddr:
433+
data, addr = self.socket_udp.recvfrom(4096)
434+
else:
446435
data = self.socket_udp.recv(4096)
447-
#print data
448-
size, command = self.parsePacketHeader(data)
449-
LOG.debug("received size: %d, command: %d"% (size, command))
450-
content = data[self.header_size:]
451-
if datapacket:
452-
return DataPacket(size, command, content)
436+
addr = None
437+
#print data
438+
size, command = self.parsePacketHeader(data)
439+
LOG.debug("received size: %d, command: %d"% (size, command))
440+
content = data[self.header_size:]
441+
if datapacket:
442+
ret = DataPacket(size, command, content)
443+
ret.addr = addr
444+
else:
445+
if useaddr:
446+
ret = addr, size, command, content
453447
else:
454-
return size, command, content
455-
except Exception, e:
456-
LOG.error('receiveMsg_UDP error: '+str(e))
457-
errorMsg = StringIO.StringIO()
458-
traceback.print_exc(file=errorMsg)
459-
LOG.error(errorMsg.getvalue())
460-
if not str(e) in self.errors:
461-
self.errors.append(str(e))
448+
ret = size, command, content
449+
return ret
462450

463451
def receiveMsg_TCP(self, datapacket = False):
464452
if self.socket_tcp is None:
465-
return None
453+
raise _error.ConnectionError("no tcp socket for receiving")
466454
note = ""
467-
#LOG.debug( "receiving...")
468455
data, readcounter = self.receive_bytes(self.socket_tcp, self.header_size)
469456
if readcounter > 1:
470457
note += "HEADER SEGMENTED INTO %s SEGMENTS!" % readcounter
@@ -493,6 +480,5 @@ def receiveMsg_TCP(self, datapacket = False):
493480
#content = struct.unpack(str(size) + 's', data)
494481
#content = content[0]
495482

496-
#LOG.debug(size, command, content)
497483

498484

ottd-serverstats.py

+25-21
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from ottd_config import config
88
from openttd.grfdb import GrfDB
99
import openttd.constants as const
10+
import socket
1011
from log import LOG
1112
VERBOSE = config.getboolean("serverstats", "verbose")
1213
SERVERS = {}
@@ -35,27 +36,30 @@ def __cmp__(self, other):
3536
class ClientGameInfo(Client):
3637
# this class implements the thread start method
3738
def run(self):
38-
self.connect(M_UDP)
39-
if len(self.errors) == 0:
40-
self.socket_udp.settimeout(10)
41-
info = self.getGameInfo()
42-
SERVERS[self.ip + ":%d" % self.port] = info
43-
if not info is None:
44-
info.ip = self.ip
45-
info.port = self.port
46-
info.newgrfs = []
47-
unknowngrfs = None
48-
if len(info.grfs) != 0:
49-
unknowngrfs = GRFS.getgrfsnotinlist(info.grfs)
50-
if len(unknowngrfs) != 0:
51-
unknowngrfs = self.getGRFInfo(unknowngrfs)
52-
for grf in info.grfs:
53-
if not GRFS.hasgrf(grf[1]) and not unknowngrfs is None:
54-
GRFS.addgrfinlist(unknowngrfs, grf[0])
55-
info.newgrfs.append((grf[0], grf[1], GRFS.getgrfname(grf)))
56-
else:
57-
SERVERS[self.ip + ":%d" % self.port] = ", ".join(self.errors)
58-
self.disconnect()
39+
try:
40+
self.connect(M_UDP)
41+
if len(self.errors) == 0:
42+
self.socket_udp.settimeout(10)
43+
info = self.getGameInfo()
44+
SERVERS[self.ip + ":%d" % self.port] = info
45+
if not info is None:
46+
info.ip = self.ip
47+
info.port = self.port
48+
info.newgrfs = []
49+
unknowngrfs = None
50+
if len(info.grfs) != 0:
51+
unknowngrfs = GRFS.getgrfsnotinlist(info.grfs)
52+
if len(unknowngrfs) != 0:
53+
unknowngrfs = self.getGRFInfo(unknowngrfs)
54+
for grf in info.grfs:
55+
if not GRFS.hasgrf(grf[1]) and not unknowngrfs is None:
56+
GRFS.addgrfinlist(unknowngrfs, grf[0])
57+
info.newgrfs.append((grf[0], grf[1], GRFS.getgrfname(grf)))
58+
else:
59+
SERVERS[self.ip + ":%d" % self.port] = ", ".join(self.errors)
60+
self.disconnect()
61+
except socket.timeout:
62+
pass
5963

6064
def savestatstofile(filename="serverstats.bin", servers=[]):
6165
if not config.getboolean("serverstats", "savehistory"):

0 commit comments

Comments
 (0)