def ping(self, server, relposinlist=0.0): destport = server.port+1 # server must already have been pinged and must have sent a reply which is less time ago than EXTINFO_TIMEOUT extinfotimeout = (server.lastping and server.lastreply and ((self.t-server.lastreply) < servercommunicator.EXTINFO_TIMEOUT) and ((self.t-server.lastping) < servercommunicator.EXTINFO_TIMEOUT) and ((not server.lastextinforeply) or ((self.t-server.lastextinforeply) > servercommunicator.EXTINFO_TIMEOUT))) #TODO if server.lastping and server.lastreply: print( server.lastping, server.lastreply, (self.t-server.lastreply) < servercommunicator.EXTINFO_TIMEOUT, (self.t-server.lastping) < servercommunicator.EXTINFO_TIMEOUT, ((not server.lastextinforeply) or ((self.t-server.lastextinforeply) > servercommunicator.EXTINFO_TIMEOUT)) ) else: print(server.lastping, server.lastreply) tryaltextinfo = (not extinfotimeout) if server.usealtextinfo else extinfotimeout debug.msg(servercommunicator.DBGTAG_PING, "pinging server at %s:%d%s (sending packets to port %d)" % (server.host, server.port, ((", %sreached extinfo timeout, using %s extinfo request" % ("" if extinfotimeout else "not ", "alternative" if tryaltextinfo else "standard")) if (extinfotimeout or server.usealtextinfo or tryaltextinfo) else ""), destport)) if server.lastreply != None and server.lastping != None and server.lastreply > server.lastping: # this is the first ping after a reply has been received server.pings = 1 else: server.pings += 1 if not server.firstping: server.firstping = self.t server.lastping = self.t server.nextping = server.lastping + (config.PING_INTERVAL * (1 + (0 if server.quicktest else (relposinlist * config.PING_SPREADRATIO)))) self.packetqueue.append(packet.pingpacket((server.host, destport))) if tryaltextinfo: # reached standard-extinfo timeout, try with alternative extinfo request self.packetqueue.append(packet.altextinfopacket((server.host, destport))) else: # standard-extinfo timeout has not been reached, proceed with standard extinfo request self.packetqueue.append(packet.extinfopacket((server.host, destport)))
def run(self, funcs): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((self.addr, self.port)) sock.listen(5) while True: try: i = sock.accept() if self.accesscache.permit(i[1][0]): tt = threading.Thread(target=self.processconnection, args=(i, funcs)) tt.start() else: # connection not permitted by accesscache debug.msg(netserver.DBGTAG_REJECT, "rejecting connection from %s:%d (not permitted by accesscache)" % i[1]) try: i[0].shutdown(socket.SHUT_RDWR) except: pass try: i[0].close() except: pass except: debug.exc(self)
def run(self, funcs): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((self.addr, self.port)) sock.listen(5) while True: try: i = sock.accept() if self.accesscache.permit(i[1][0]): tt = threading.Thread(target=self.processconnection, args=(i, funcs)) tt.start() else: # connection not permitted by accesscache debug.msg( netserver.DBGTAG_REJECT, "rejecting connection from %s:%d (not permitted by accesscache)" % i[1]) try: i[0].shutdown(socket.SHUT_RDWR) except: pass try: i[0].close() except: pass except: debug.exc(self)
def readinfo(self, buf): try: numclients_ = buf.getint() attrs_ = buf.getint() if attrs_ != 5: return False, "attrs is not 5" version_ = buf.getint() gamemode_ = buf.getint() remaining_ = buf.getint() # TODO: switch protocol versions (in sooner versions, remaining_ is in minutes) maxclients_ = buf.getint() mastermode_ = buf.getint() map_ = buf.getstring() desc_ = buf.getstring() except EndOfBufError: return False, "end of buf unexpectedly reached" debug.msg(server.DBGTAG_READINFO, "%s:%d: numclients=%d, attrs=%d, version=%d, gamemode=%d, remaining=%d, maxclients=%d, mastermode=%d, map=\"%s\", desc=\"%s\"" % (self.host, self.port, numclients_, attrs_, version_, gamemode_, remaining_, maxclients_, mastermode_, map_, desc_)) self.numclients = numclients_ self.version = version_ self.gamemode = gamemode_ self.remaining = remaining_ self.maxclients = maxclients_ self.mastermode = mastermode_ self.map = map_ self.desc = tools.safe(desc_) return True, ""
def pingservers(self): kicklist = [] for name in self.lists: clist = self.lists[name] total = float(clist.len()) n = 0.0 for server in clist.releasingiterator(): if ( (not server.persistent) or name != self.pendingservers_key ) and server.lastping != None and server.nextping != None and server.nextping < self.t and ( server.lastreply == None or server.lastreply < server.lastping) and server.pings >= ( 1 if server.quicktest else config.PINGS_GIVEUP): # server is either not persistent or is not in pending servers list (it will be added there) has been pinged once or more, time is reached for a new ping, but the number of pings before giving up is exceeded. kick server. kicklist.append(server) elif server.nextping == None or server.nextping < self.t: # last ping has been too long ago, or server was never pinged. ping it. self.ping(server, n / total) n += 1 if len(kicklist) > 0: debug.msg( servercommunicator.DBGTAG_KICK, "kicking out %d servers from %s list" % (len(kicklist), name)) for server in kicklist: self.kick(clist, name, server) del kicklist[:]
def readextinfo(self, buf): try: ack_ = buf.getint() if ack_ != packet.EXT_ACK: return False, "EXT_ACK (%d) expected, got %d instead" % (packet.EXT_ACK, ack_) version_ = buf.getint() if version_ != packet.EXT_VERSION: return False, "received unknown extinfo version %d" % version_ error_ = buf.getint() if error_ != packet.EXT_NO_ERROR: return False, "extinfo request contains errors, expected EXT_NO_ERROR (%d), got %d instead" % (packet.EXT_NO_ERROR, error_) content_ = buf.getint() if content_ == packet.EXT_PLAYERSTATS_RESP_IDS: e = debug.tagenabled(server.DBGTAG_CLIENTCNSDUMP) if e: s = "" n = 0 while buf.available(): cn = buf.getint() self.clients.keep(cn) # keep this player if e: s += " " + str(cn) n += 1 self.clients.keep() # remove players not called keep() on if e: debug.msg(server.DBGTAG_CLIENTCNSDUMP, "%s:%d: received %d cns:%s" % (self.host, self.port, n, s)) elif content_ == packet.EXT_PLAYERSTATS_RESP_STATS: cn = buf.getint() ping = buf.getint() name = buf.getstring() team = buf.getstring() frags = buf.getint() flags = buf.getint() deaths = buf.getint() teamkills = buf.getint() damage = buf.getint() health = buf.getint() armour = buf.getint() gunselect = buf.getint() priv = buf.getint() state = buf.getint() ip = (buf.read(), buf.read(), buf.read()) c = self.clients.get(cn) c.name = name c.team = team c.frags = frags c.flags = flags c.priv = priv c.state = state c.ip = ip if debug.tagenabled(server.DBGTAG_CLIENTDUMP): debug.msg(server.DBGTAG_CLIENTDUMP, "%s:%d: received client: cn=%d, name=\"%s\", team=\"%s\", frags=%d, flags=%d, priv=%d, ip=%d.%d.%d.x" % ((self.host, self.port, cn, name, team, frags, flags, priv)+ip)) else: return False, "invalid content type, expected EXT_PLAYERSTATS_RESP_IDS (%d) or EXT_PLAYERSTATS_RESP_STATS (%d), got %d instead" % (packet.EXT_PLAYERSTATS_RESP_IDS, packet.EXT_PLAYERSTATS_RESP_STATS, content_) except EndOfBufError: return False, "end of buf unexpectedly reached" return True, ""
def processdata(self, p): debug.msg(servercommunicator.DBGTAG_RECV, "received %d bytes from %s:%d" % ((len(p.data), ) + p.addr)) host = p.addr[0] servport = p.addr[1] - 1 plist = self.lists[self.pendingservers_key] s = plist.find(host, servport) if s: # server from pending servers list has replied, move it to registered servers list rlist = self.lists[self.registeredservers_key] self.register(s, rlist, plist) else: # sender is not in pending servers list, look through other lists for name in self.lists: if name == self.pendingservers_key: continue clist = self.lists[name] s = clist.find(host, servport) if s: break if not s: #if no server was found in any list, return. debug.msg( servercommunicator.DBGTAG_UNKNOWNSERVER, "received %d bytes from an unknown server at %s:%d (packet sent from port %d)" % (len(p.data), host, servport, p.addr[1])) return # TODO maybe add the server directly, even though it did not announce itself via regserv command? s.lastreply = self.t s.read( buf(p.data), self.t ) # hand over current time (self.t) so server can set s.lastextinforeply if this is extinfo
def kick(self, clist, name, server): debug.msg(servercommunicator.DBGTAG_MOVESERVER if server.persistent else servercommunicator.DBGTAG_KICKSERVER, "%s server at %s:%d from %s list%s (first ping: %s, last ping: %s, last reply: %s)" % ("moving persistent" if server.persistent else "kicking out", server.host, server.port, name, (" to %s list" % self.pendingservers_key) if server.persistent else "", ("never" if server.firstping == None else ("%f seconds ago" % (self.t-server.firstping))), ("never" if server.lastping == None else ("%f seconds ago" % (self.t-server.lastping))), ("never" if server.lastreply == None else ("%f seconds ago" % (self.t-server.lastreply))))) clist.remove(server) if server.persistent: self.lists[self.pendingservers_key].append_once(server) else: server.onremove()
def updatefrommaster(self): s = self.connect() s.send("list\n") self.fetch(s) s.close() debug.msg(masterclient.DBGTAG_FETCHED, "fetched %d servers from master" % self.list.len())
def append_once(self, server): if not self.exists(server): if not self._isbanned(server): self._append(server) else: debug.msg( serverlist.DBGTAG_REFUSED, "refused a banned server at %s:%d" % (server.host, server.port))
def register(self, server, rlist, plist): plist.removeall(server) rlist.append_once(server) debug.msg( servercommunicator.DBGTAG_SUCCREG, "registration of server %s:%d successful" % (server.host, server.port)) server.quicktest = False server.onregister()
def ping(self, server, relposinlist=0.0): destport = server.port + 1 # server must already have been pinged and must have sent a reply which is less time ago than EXTINFO_TIMEOUT extinfotimeout = ( server.lastping and server.lastreply and ((self.t - server.lastreply) < servercommunicator.EXTINFO_TIMEOUT) and ((self.t - server.lastping) < servercommunicator.EXTINFO_TIMEOUT) and ((not server.lastextinforeply) or ((self.t - server.lastextinforeply) > servercommunicator.EXTINFO_TIMEOUT))) #TODO if server.lastping and server.lastreply: print(server.lastping, server.lastreply, (self.t - server.lastreply) < servercommunicator.EXTINFO_TIMEOUT, (self.t - server.lastping) < servercommunicator.EXTINFO_TIMEOUT, ((not server.lastextinforeply) or ((self.t - server.lastextinforeply) > servercommunicator.EXTINFO_TIMEOUT))) else: print(server.lastping, server.lastreply) tryaltextinfo = ( not extinfotimeout) if server.usealtextinfo else extinfotimeout debug.msg( servercommunicator.DBGTAG_PING, "pinging server at %s:%d%s (sending packets to port %d)" % (server.host, server.port, ((", %sreached extinfo timeout, using %s extinfo request" % ("" if extinfotimeout else "not ", "alternative" if tryaltextinfo else "standard")) if (extinfotimeout or server.usealtextinfo or tryaltextinfo) else ""), destport)) if server.lastreply != None and server.lastping != None and server.lastreply > server.lastping: # this is the first ping after a reply has been received server.pings = 1 else: server.pings += 1 if not server.firstping: server.firstping = self.t server.lastping = self.t server.nextping = server.lastping + ( config.PING_INTERVAL * (1 + (0 if server.quicktest else (relposinlist * config.PING_SPREADRATIO)))) self.packetqueue.append(packet.pingpacket((server.host, destport))) if tryaltextinfo: # reached standard-extinfo timeout, try with alternative extinfo request self.packetqueue.append( packet.altextinfopacket((server.host, destport))) else: # standard-extinfo timeout has not been reached, proceed with standard extinfo request self.packetqueue.append( packet.extinfopacket((server.host, destport)))
def __str__(self, *args): s = "" for p in self.parts: if type(p) == types.StringType: s += p else: try: s += p.__str__(*args) except: debug.msg(guiline.DBGTAG_STRPARTERROR, "was getting string from guicommand: %s (re-raising this exception)" % repr(p)) raise return s
def processline(self, line): if line[:len(masterclient.ADDSERVER_COMMAND)] != masterclient.ADDSERVER_COMMAND: debug.msg(masterclient.DBGTAG_INVALID, "received invalid line from master, does not start with \"%s\": %s" % (masterclient.ADDSERVER_COMMAND, line)) return a = line[len(masterclient.ADDSERVER_COMMAND)+1:] p = a.split(" ") if len(p) < 2: debug.msg(masterclient.DBGTAG_INVALID, "received invalid line from master, does not contain 2 arguments: %s" % line) return host = p[0] port = int(p[1]) self.list.add_from_master(host, port)
def check(self): if not self.banned: return dellist = [] for s in self.list.iterator(): if self._isbanned(s): dellist.append(s) if len(dellist): debug.msg(serverlist.DBGTAG_DELBANNEDSERVERS, "removing %d banned servers" % len(dellist)) for s in dellist: debug.msg(serverlist.DBGTAG_DELBANNED, "removing banned server at %s:%d" % (s.host, s.port)) self.remove(s) s.onremove()
def main(): debug.msg(True, "--- gamemod masterserver %s starting up ---" % gamemod.VERSION) g = gamemod() try: while True: time.sleep(1) # TODO except KeyboardInterrupt: msg = "exiting (KeyboardInterrupt) ..."; try: debug.msg(True, msg) except: try: log.out("(debug.msg failed, using log.out) " + msg) except: print("(debug.msg and log.out failed, using print) " + msg) sys.exit()
def readinfo(self, buf): try: numclients_ = buf.getint() attrs_ = buf.getint() if attrs_ != 5: return False, "attrs is not 5" version_ = buf.getint() gamemode_ = buf.getint() remaining_ = buf.getint( ) # TODO: switch protocol versions (in sooner versions, remaining_ is in minutes) maxclients_ = buf.getint() mastermode_ = buf.getint() map_ = buf.getstring() desc_ = buf.getstring() except EndOfBufError: return False, "end of buf unexpectedly reached" if int(time.time()) - latest_check > 60: for serv in known_servers.keys(): if int(time.time()) - known_servers[serv] > 60: del known_servers[serv] print("Server removed: ID: %s" % serv) server_id = "%s:%s" % (self.host, self.port) if (server_id not in known_servers.keys()): print( "Server added: IP: %s, Port: %d, Description: \"%s\", Map: \"%s\", ID: %s, Clients: %d, Version: %d, Attrs: %d, Gamemode: %d, Remaining: %d, Max. Clients: %d, Mastermode: %d\n" % (self.host, self.port, desc_.replace("\r\n", "").replace( "\n", "").decode('utf-8', 'ignore'), map_, server_id, numclients_, version_, attrs_, gamemode_, remaining_, maxclients_, mastermode_)) # TODO: Translate numbers to actual words. known_servers[server_id] = int(time.time()) debug.msg( server.DBGTAG_READINFO, "%s:%d: id=%s-%d, numclients=%d, attrs=%d, version=%d, gamemode=%d, remaining=%d, maxclients=%d, mastermode=%d, map=\"%s\", desc=\"%s\"" % (self.host, self.port, self.host, self.port, numclients_, attrs_, version_, gamemode_, remaining_, maxclients_, mastermode_, map_, desc_)) self.numclients = numclients_ self.version = version_ self.gamemode = gamemode_ self.remaining = remaining_ self.maxclients = maxclients_ self.mastermode = mastermode_ self.map = map_ self.desc = tools.safe(desc_) return True, ""
def sendqueue(self): before = len(self.packetqueue) if before: while len(self.packetqueue): p = self.packetqueue.popleft() try: self.socket.sendto(p.data, p.addr) except: self.packetqueue.appendleft(p) break #print("sending packet to %s:%d" % (p.addr[0], p.addr[1])) #self.socket.sendto(p.data, 0, p.addr) now = len(self.packetqueue) if before != now: debug.msg(servercommunicator.DBGTAG_SENT, "sent %d of %d packets (%d packets left)" % (before-now, before, now))
def sendqueue(self): before = len(self.packetqueue) if before: while len(self.packetqueue): p = self.packetqueue.popleft() try: self.socket.sendto(p.data, p.addr) except: self.packetqueue.appendleft(p) break #print("sending packet to %s:%d" % (p.addr[0], p.addr[1])) #self.socket.sendto(p.data, 0, p.addr) now = len(self.packetqueue) if before != now: debug.msg( servercommunicator.DBGTAG_SENT, "sent %d of %d packets (%d packets left)" % (before - now, before, now))
def main(): debug.msg(True, "--- gamemod masterserver %s starting up ---" % gamemod.VERSION) g = gamemod() try: while True: time.sleep(1) # TODO except KeyboardInterrupt: msg = "exiting (KeyboardInterrupt) ..." try: debug.msg(True, msg) except: try: log.out("(debug.msg failed, using log.out) " + msg) except: print("(debug.msg and log.out failed, using print) " + msg) sys.exit()
def processline(self, line): if line[:len(masterclient.ADDSERVER_COMMAND )] != masterclient.ADDSERVER_COMMAND: debug.msg( masterclient.DBGTAG_INVALID, "received invalid line from master, does not start with \"%s\": %s" % (masterclient.ADDSERVER_COMMAND, line)) return a = line[len(masterclient.ADDSERVER_COMMAND) + 1:] p = a.split(" ") if len(p) < 2: debug.msg( masterclient.DBGTAG_INVALID, "received invalid line from master, does not contain 2 arguments: %s" % line) return host = p[0] port = int(p[1]) self.list.add_from_master(host, port)
def pingservers(self): kicklist = [] for name in self.lists: clist = self.lists[name] total = float(clist.len()) n = 0.0 for server in clist.releasingiterator(): if ((not server.persistent) or name != self.pendingservers_key) and server.lastping != None and server.nextping != None and server.nextping < self.t and (server.lastreply == None or server.lastreply < server.lastping) and server.pings >= (1 if server.quicktest else config.PINGS_GIVEUP): # server is either not persistent or is not in pending servers list (it will be added there) has been pinged once or more, time is reached for a new ping, but the number of pings before giving up is exceeded. kick server. kicklist.append(server) elif server.nextping == None or server.nextping < self.t: # last ping has been too long ago, or server was never pinged. ping it. self.ping(server, n/total) n += 1 if len(kicklist) > 0: debug.msg(servercommunicator.DBGTAG_KICK, "kicking out %d servers from %s list" % (len(kicklist), name)) for server in kicklist: self.kick(clist, name, server) del kicklist[:]
def kick(self, clist, name, server): debug.msg( servercommunicator.DBGTAG_MOVESERVER if server.persistent else servercommunicator.DBGTAG_KICKSERVER, "%s server at %s:%d from %s list%s (first ping: %s, last ping: %s, last reply: %s)" % ("moving persistent" if server.persistent else "kicking out", server.host, server.port, name, (" to %s list" % self.pendingservers_key) if server.persistent else "", ("never" if server.firstping == None else ("%f seconds ago" % (self.t - server.firstping))), ("never" if server.lastping == None else ("%f seconds ago" % (self.t - server.lastping))), ("never" if server.lastreply == None else ("%f seconds ago" % (self.t - server.lastreply))))) clist.remove(server) if server.persistent: self.lists[self.pendingservers_key].append_once(server) else: server.onremove()
def update(self, catch=True, force=False): # update gui (read it from file) try: f = open(self.path, "r") newguilines = [] errors = [] warnings = [] n = 0 # line number for line in f: n += 1 self.curline = n gl = guiline( self.g, line[:-1] if (len(line) > 0 and line[-1] == "\n") else l) for w in gl.warnings: warnings.append("warning in line %d: %s" % (n, w)) if gl.error: errors.append("skipping line %d: %s" % (n, gl.error)) else: newguilines.append(gl) f.close() exchange = force or (not len(errors)) for w in warnings: debug.msg(gui.DBGTAG_WARNING, w) debug.msg( gui.DBGTAG_WARNINGS, "%s warnings while reading gui" % (str(len(warnings)) if len(warnings) else "no")) for e in errors: debug.msg(gui.DBGTAG_ERROR, e) debug.msg( gui.DBGTAG_ERRORS, "%s errors while reading gui%s, %s" % (str(len(errors)) if len(errors) else "no", " (ignoring these lines)" if len(errors) else "", "applying new guilines list" if exchange else "cancelling update")) if exchange: self.guilines.exchange(newguilines) return exchange, "%d lines read, %d errors (skipping lines with errors), %d warnings" % ( len(newguilines), len(errors), len(warnings)) except: try: f.close() except: pass if catch: debug.exc(self) else: raise return False, "internal errors occurred"
def add_once(self, host, port, selfreg=False, suggested=False, persistent=False, force=False, checkport=True, file=None, quicktest=False): # add server if it doesn't already exist, return (serverobject, existed) if (not force) and self._isbanned(host, port): debug.msg(serverlist.DBGTAG_REFUSED, "refused a banned server at %s:%d" % (host, port)) return None, False else: if checkport and (port < 0 or port > 65534): debug.msg(serverlist.DBGTAG_INVALIDPORT, "trying to add a new server with an invalid port: %s:%d" % (host, port)) return s = self.find(host, port) if s: existed = True else: s = server(host, port) self._append(s) existed = False if selfreg: s.selfreg = True # whether this server has registered itself to gamemod (and not arrived via sauerbraten.org) if (not existed) and suggested: s.suggested = True # whether this server has been suggested to gamemod and was unknown before (and not arrived via sauerbraten.org) if persistent: s.persistent = True # whether this server should never be kicked from the pending servers list if file: s.fromfile = file if (not existed) and quicktest: s.quicktest = True # whether this server should be tested for registration quickly (= kick it if it does not already reply within one request and config.PING_INTERVAL) return s, existed
def add_once( self, host, port, selfreg=False, suggested=False, persistent=False, force=False, checkport=True, file=None, quicktest=False ): # add server if it doesn't already exist, return (serverobject, existed) if (not force) and self._isbanned(host, port): debug.msg(serverlist.DBGTAG_REFUSED, "refused a banned server at %s:%d" % (host, port)) return None, False else: if checkport and (port < 0 or port > 65534): debug.msg( serverlist.DBGTAG_INVALIDPORT, "trying to add a new server with an invalid port: %s:%d" % (host, port)) return s = self.find(host, port) if s: existed = True else: s = server(host, port) self._append(s) existed = False if selfreg: s.selfreg = True # whether this server has registered itself to gamemod (and not arrived via sauerbraten.org) if (not existed) and suggested: s.suggested = True # whether this server has been suggested to gamemod and was unknown before (and not arrived via sauerbraten.org) if persistent: s.persistent = True # whether this server should never be kicked from the pending servers list if file: s.fromfile = file if (not existed) and quicktest: s.quicktest = True # whether this server should be tested for registration quickly (= kick it if it does not already reply within one request and config.PING_INTERVAL) return s, existed
def read(self, buf, t): debug.msg( server.DBGTAG_READ, "%s:%d: reading %d bytes" % (self.host, self.port, buf.len())) if debug.tagenabled(server.DBGTAG_BUFDUMP): pos = buf.pos() s = "" while buf.available(): try: s += " " + str(buf.getint()) except EndOfBufError: break debug.msg(server.DBGTAG_BUFDUMP, "%s:%d: buf:%s" % (self.host, self.port, s)) buf.seek(pos) req = buf.read() if (req == ord(packet.ALTEXTINFO_BYTE)) or (not req): # (standard/alternative) extinfo buf.skip( len(packet.ALTEXTINFO_DATA if (req == packet.ALTEXTINFO_BYTE) else packet.EXTINFO_DATA) - 1) succ, msg = self.readextinfo(buf) if succ: self.lastextinforeply = t self.usealtextinfo = (req == packet.ALTEXTINFO_BYTE) else: succ, msg = self.readinfo(buf) if not succ: debug.msg( server.DBGTAG_READFAIL, "%s:%d: reading %d bytes of %sinfo failed: %s" % (self.host, self.port, buf.len(), "" if req else "ext", msg))
def processdata(self, p): debug.msg(servercommunicator.DBGTAG_RECV, "received %d bytes from %s:%d" % ((len(p.data),)+p.addr)) host = p.addr[0] servport = p.addr[1] - 1 plist = self.lists[self.pendingservers_key] s = plist.find(host, servport) if s: # server from pending servers list has replied, move it to registered servers list rlist = self.lists[self.registeredservers_key] self.register(s, rlist, plist) else: # sender is not in pending servers list, look through other lists for name in self.lists: if name == self.pendingservers_key: continue clist = self.lists[name] s = clist.find(host, servport) if s: break if not s: #if no server was found in any list, return. debug.msg(servercommunicator.DBGTAG_UNKNOWNSERVER, "received %d bytes from an unknown server at %s:%d (packet sent from port %d)" % (len(p.data), host, servport, p.addr[1])) return # TODO maybe add the server directly, even though it did not announce itself via regserv command? s.lastreply = self.t s.read(buf(p.data), self.t) # hand over current time (self.t) so server can set s.lastextinforeply if this is extinfo
def onrequest(self, line, addr, build): # return (reply, close) if line == guiprovider.LIST_REQUEST: debug.msg( guiprovider.DBGTAG_REQUEST, "%s request from %s:%d (%sbuild)" % ((line, ) + addr + ("" if build else "don't ", ))) self.counter.add(addr[0]) s = (self.request() if build else True) debug.msg( guiprovider.DBGTAG_REQUEST, "sending reply to %s request to %s:%d" % ((line, ) + addr)) return s, True elif line == guiprovider.READABLELIST_REQUEST: debug.msg( guiprovider.DBGTAG_REQUEST, "%s request from %s:%d (%sbuild)" % ((line, ) + addr + ("" if build else "don't ", ))) s = (self.request(True) if build else True) debug.msg( guiprovider.DBGTAG_REQUEST, "sending reply to %s request to %s:%d" % ((line, ) + addr)) return s, True return None, False
def update(self, catch=True, force=False): # update gui (read it from file) try: f = open(self.path, "r") newguilines = [] errors = [] warnings = [] n = 0 # line number for line in f: n += 1 self.curline = n gl = guiline(self.g, line[:-1] if (len(line) > 0 and line[-1]=="\n") else l) for w in gl.warnings: warnings.append("warning in line %d: %s" % (n, w)) if gl.error: errors.append("skipping line %d: %s" % (n, gl.error)) else: newguilines.append(gl) f.close() exchange = force or (not len(errors)) for w in warnings: debug.msg(gui.DBGTAG_WARNING, w) debug.msg(gui.DBGTAG_WARNINGS, "%s warnings while reading gui" % (str(len(warnings)) if len(warnings) else "no")) for e in errors: debug.msg(gui.DBGTAG_ERROR, e) debug.msg(gui.DBGTAG_ERRORS, "%s errors while reading gui%s, %s" % (str(len(errors)) if len(errors) else "no", " (ignoring these lines)" if len(errors) else "", "applying new guilines list" if exchange else "cancelling update")) if exchange: self.guilines.exchange(newguilines) return exchange, "%d lines read, %d errors (skipping lines with errors), %d warnings" % (len(newguilines), len(errors), len(warnings)) except: try: f.close() except: pass if catch: debug.exc(self) else: raise return False, "internal errors occurred"
def read(self, buf, t): debug.msg(server.DBGTAG_READ, "%s:%d: reading %d bytes" % (self.host, self.port, buf.len())) if debug.tagenabled(server.DBGTAG_BUFDUMP): pos = buf.pos() s = "" while buf.available(): try: s += " " + str(buf.getint()) except EndOfBufError: break debug.msg(server.DBGTAG_BUFDUMP, "%s:%d: buf:%s" % (self.host, self.port, s)) buf.seek(pos) req = buf.read() if (req == ord(packet.ALTEXTINFO_BYTE)) or (not req): # (standard/alternative) extinfo buf.skip(len(packet.ALTEXTINFO_DATA if (req == packet.ALTEXTINFO_BYTE) else packet.EXTINFO_DATA)-1) succ, msg = self.readextinfo(buf) if succ: self.lastextinforeply = t self.usealtextinfo = (req == packet.ALTEXTINFO_BYTE) else: succ, msg = self.readinfo(buf) if not succ: debug.msg(server.DBGTAG_READFAIL, "%s:%d: reading %d bytes of %sinfo failed: %s" % (self.host, self.port, buf.len(), "" if req else "ext", msg))
def processconnection(self, i, funcs): (sock, addr) = i (host, port) = addr debug.msg(netserver.DBGTAG, "connection from %s:%d" % (host, port)) sock.settimeout(2) closecon = False try: while True: lines, err = self.recv(sock) if err: debug.msg( netserver.DBGTAG_RECVFAIL, "an error occured while receiving request from %s:%d" % (host, port)) break for line in lines: if len(line) <= 0: debug.msg( netserver.DBGTAG_EMPTYLINE, "empty line received from %s:%d, skipping" % (host, port)) continue debug.msg(netserver.DBGTAG_TRAFFIC, "received from %s:%d: %s" % (host, port, line)) reply = None close = False cachedreply = self.cache.find(line) build = not bool(cachedreply) for func in funcs: r = func(line, addr, build) if not r: continue (creply, cclose) = r if build: (reply, close) = r if creply or cclose: break if cachedreply: (reply, close) = cachedreply closecon = closecon or close if reply: replytext, n, err = self.send( sock, reply, (debug.tagenabled(netserver.DBGTAG_REPLYTEXT) or ((not cachedreply) and replycache.enabled(line)))) if not err: debug.msg( netserver.DBGTAG_REPLY, "sent %sreply with length %d to %s:%d" % (("cached " if cachedreply else ""), n, host, port)) if replytext != None: debug.msg( netserver.DBGTAG_REPLYTEXT, "sent %sreply to %s:%d: (starts next line)\n%s\n --- end of reply ---" % (("cached " if cachedreply else ""), host, port, replytext)) if (not cachedreply) and replycache.enabled(line): self.cache.cache(line, replytext, close) else: debug.msg( netserver.DBGTAG_SENDFAIL, "an error occured while sending reply to %s:%d" % (host, port)) elif close: # no reply, but close - forceclose debug.msg( netserver.DBGTAG_FORCECLOSE, "force-closing connection to %s:%d without reply" % (host, port)) break else: debug.msg( netserver.DBGTAG_UNKNOWN, "no reply available for line received from %s:%d: %s" % (host, port, line)) if closecon: break except: debug.msg( netserver.DBGTAG, "an error occured while processing connection with %s:%d" % (host, port)) debug.exc() self.accesscache.end(host) shut = False try: sock.shutdown(socket.SHUT_RDWR) shut = True except: pass # remote has already shut down connection try: sock.close() except: pass debug.msg( netserver.DBGTAG, "connection %s:%d closed (shutdown %s)" % (host, port, "succeeded" if shut else "failed"))
def readextinfo(self, buf): try: ack_ = buf.getint() if ack_ != packet.EXT_ACK: return False, "EXT_ACK (%d) expected, got %d instead" % ( packet.EXT_ACK, ack_) version_ = buf.getint() if version_ != packet.EXT_VERSION: return False, "received unknown extinfo version %d" % version_ error_ = buf.getint() if error_ != packet.EXT_NO_ERROR: return False, "extinfo request contains errors, expected EXT_NO_ERROR (%d), got %d instead" % ( packet.EXT_NO_ERROR, error_) content_ = buf.getint() if content_ == packet.EXT_PLAYERSTATS_RESP_IDS: e = debug.tagenabled(server.DBGTAG_CLIENTCNSDUMP) if e: s = "" n = 0 while buf.available(): cn = buf.getint() self.clients.keep(cn) # keep this player if e: s += " " + str(cn) n += 1 self.clients.keep() # remove players not called keep() on if e: debug.msg( server.DBGTAG_CLIENTCNSDUMP, "%s:%d: received %d cns:%s" % (self.host, self.port, n, s)) elif content_ == packet.EXT_PLAYERSTATS_RESP_STATS: cn = buf.getint() ping = buf.getint() name = buf.getstring() team = buf.getstring() frags = buf.getint() flags = buf.getint() deaths = buf.getint() teamkills = buf.getint() damage = buf.getint() health = buf.getint() armour = buf.getint() gunselect = buf.getint() priv = buf.getint() state = buf.getint() ip = (buf.read(), buf.read(), buf.read()) c = self.clients.get(cn) c.name = name c.team = team c.frags = frags c.flags = flags c.priv = priv c.state = state c.ip = ip if debug.tagenabled(server.DBGTAG_CLIENTDUMP): debug.msg( server.DBGTAG_CLIENTDUMP, "%s:%d: received client: cn=%d, name=\"%s\", team=\"%s\", frags=%d, flags=%d, priv=%d, ip=%d.%d.%d.x" % ((self.host, self.port, cn, name, team, frags, flags, priv) + ip)) else: return False, "invalid content type, expected EXT_PLAYERSTATS_RESP_IDS (%d) or EXT_PLAYERSTATS_RESP_STATS (%d), got %d instead" % ( packet.EXT_PLAYERSTATS_RESP_IDS, packet.EXT_PLAYERSTATS_RESP_STATS, content_) except EndOfBufError: return False, "end of buf unexpectedly reached" return True, ""
def onrequest(self, line, addr, build): if line == statsprovider.STATS_REQUEST: debug.msg(statsprovider.DBGTAG_REQUEST, "%s request from %s:%d" % ((line, ) + addr)) return self.jsonstats(), True
def fetch(self, catch, path, synclists, oldlist, needport=True, add_once=False): # sync synclist (read it from file, add unexisting servers, remove servers no more in file (compare read items with oldlist)) and return a list of fetched items (which will be used as oldlist next time debug.msg( additionalservers.DBGTAG_UPDATING, "updating %d server list%s with servers from file %s" % (len(synclists), "s" if len(synclists) > 1 else "", path)) try: f = open(path, "r") newlist = [] addlist = [] n = 0 # line number errors = 0 for line_ in f: n += 1 if line_[-1] == "\n": line = line_[:-1] else: line = line_ if len(line) <= 0 or line.startswith( additionalservers.COMMENT_STR): continue p = line.split(" ") if len(p) < 2 and needport: debug.msg( additionalservers.DBGTAG_INVALID, "can't fetch server from line %d in file %s" % (n, path)) errors += 1 else: whost = p[0] if len(p) >= 2: try: port = int(p[1]) except: debug.msg( additionalservers.DBGTAG_INVALID, "can't fetch port for server at %s from line %d in file %s" % (whost, n, path)) errors += 1 continue else: port = "*" try: host = socket.gethostbyname(whost) except: debug.msg( additionalservers.DBGTAG_INVALID, "can't resolve host %s for server at %s:%s from line %d in file %s" % (whost, whost, str(port), n, path)) errors += 1 continue item = (host, port) newlist.append(item) addlist.append(item) f.close() dellist = [] for old in oldlist: if addlist.count(old): addlist.remove(old) # was added already else: dellist.append(old) # was removed from file for (synclist, listname) in synclists: for (host, port) in dellist: s = synclist.find(host, port) if s and s.fromfile == path: synclist.removeall(s) debug.msg( additionalservers.DBGTAG_REMOVED, "removed server at %s:%s from %s servers list" % (host, str(port), listname)) for (host, port) in addlist: if add_once: # don't add this anywhere if it already exists in any of the supplied synclists skip = False for (list_, name) in synclists: if list_.find(host, port): skip = True break if skip: debug.msg( additionalservers.DBGTAG_SKIP, "skipping server %s:%s from file %s because it already exists in the supplied synclists" % (host, str(port), path)) continue debug.msg( additionalservers.DBGTAG_ADD, "adding server at %s:%s to %s servers list" % (host, str(port), synclists[0][1])) synclists[0][0].add_from_file( host, (port if (type(port) == types.IntType) else None), file=path) debug.msg( additionalservers.DBGTAG_UPDATED, "updated %d server list%s with servers from file %s: %d items fetched from %d lines, %d errors, %d items added, %d items deleted" % (len(synclists), "s" if len(synclists) > 1 else "", path, len(newlist), n, errors, len(addlist), len(dellist))) return True, "%d items fetched from %d lines, %d errors (skipping lines with errors), %d items added, %d items deleted" % ( len(newlist), n, errors, len(addlist), len(dellist)), newlist except: if catch: debug.exc(self) try: f.close() except: pass else: try: f.close() except: pass raise return False, "internal errors occurred", oldlist
def onrequest(self, line, addr, build): if line == statsprovider.STATS_REQUEST: debug.msg(statsprovider.DBGTAG_REQUEST, "%s request from %s:%d" % ((line,)+addr)) return self.jsonstats(), True
def parse(self, s, standalone): start_i = 0 while start_i < len(s): # skip whitespaces in front b = s[start_i] if b != "\t" and b != " ": break start_i += 1 self.leadingwhitespaces = s[:start_i] comment_i = s.find("//", start_i) if comment_i > -1: s = s[:comment_i] for i in guiline.GUI_REPLACEMENTS: s = s.replace(i, guiline.GUI_REPLACEMENTS[i]) while True: i = s.find(self.gui.GUICOMMAND_PREFIX, start_i) if i < 0: p = s[start_i:] if len(p): self.parts.append(p) # append rest of the line (or the whole line if it does not contain any guicommands) break argpart_i = s.find(self.gui.GUICOMMAND_ARGS_PREFIX, i+len(self.gui.GUICOMMAND_PREFIX)) if argpart_i < 0: return "missing arguments-opening \"%s\" after guicommand-prefix \"%s\" and guicommand-name" % (self.gui.GUICOMMAND_ARGS_PREFIX, self.gui.GUICOMMAND_PREFIX) cmd = s[i+len(self.gui.GUICOMMAND_PREFIX):argpart_i] args_i = argpart_i+len(self.gui.GUICOMMAND_ARGS_PREFIX) endargs_i = None whole = guicommand.args_whole(cmd) while True: end = False if s.startswith(self.gui.ARGS_NOMODIFIERS_MODIFIER, args_i): # allow no more modifiers args_i += len(self.gui.ARGS_NOMODIFIERS_MODIFIER) end = True elif s.startswith(self.gui.ARGS_TILEOL_MODIFIER, args_i): # read argument until ")" at end of line endargs_i = False args_i += len(self.gui.ARGS_TILEOL_MODIFIER) elif s.startswith(self.gui.ARGS_WHOLE_MODIFIER, args_i): # read whole argument list as one string whole = True args_i += len(self.gui.ARGS_WHOLE_MODIFIER) else: break if end: break if endargs_i == None: # search for end of args endargs_i = s.find(self.gui.GUICOMMAND_ARGS_SUFFIX, args_i) if endargs_i < 0: return "missing arguments-closing \"%s\" at end of command" % gui.GUICOMMAND_ARGS_SUFFIX elif endargs_i == False: # TILEOL modifier is used endargs_i = len(s)-len(self.gui.GUICOMMAND_ARGS_SUFFIX) if s[endargs_i:endargs_i+len(self.gui.GUICOMMAND_ARGS_SUFFIX)] != self.gui.GUICOMMAND_ARGS_SUFFIX: return "missing arguments-closing \"%s\" at end of line" % gui.GUICOMMAND_ARGS_SUFFIX argstring = s[args_i:endargs_i] if not len(argstring): args = [] elif whole: # WHOLE modifier is used args = [argstring] else: args = argstring.split(self.gui.GUICOMMAND_ARGS_SEPERATOR) args_min = guicommand.args_min(cmd) if len(args) < args_min and ((not whole) or (not len(args))): return "guicommand \"%s\" requires at least %d argument%s" % (cmd, args_min, "s" if args_min > 1 else "") if guicommand.args_guiline(cmd): args_ = [] for a in args: gl = guiline(self.g, a, False) if gl.error: return "in argument of guicommand \"%s\": %s" % (cmd, gl.error) args_.append(gl) args = args_ item, msg = guicommand.get(self.g, cmd, args, standalone) # item may either be a guicommand instance or just a string (in case a guicommand would always result in the same string) if item == None: return "guicommand \"%s\": %s" % (cmd, msg) p = s[start_i:i] if len(p): self.parts.append(p) #self.parts.append("guicommand \"%s\" with %d args: \"%s\"" % (cmd, len(args), "\", \"".join(args))) self.parts.append(item) start_i = endargs_i+len(self.gui.GUICOMMAND_ARGS_SUFFIX) # start search for next guicommand at position where the last one ended if debug.tagenabled(guiline.DBGTAG_DUMPPARTS): debug.msg(guiline.DBGTAG_DUMPPARTS, "parsed %d parts: %s" % (len(self.parts), repr(self.parts)))
def register(self, server, rlist, plist): plist.removeall(server) rlist.append_once(server) debug.msg(servercommunicator.DBGTAG_SUCCREG, "registration of server %s:%d successful" % (server.host, server.port)) server.quicktest = False server.onregister()
def fetch(self, catch, path, synclists, oldlist, needport=True, add_once=False): # sync synclist (read it from file, add unexisting servers, remove servers no more in file (compare read items with oldlist)) and return a list of fetched items (which will be used as oldlist next time debug.msg(additionalservers.DBGTAG_UPDATING, "updating %d server list%s with servers from file %s" % (len(synclists), "s" if len(synclists) > 1 else "", path)) try: f = open(path, "r") newlist = [] addlist = [] n = 0 # line number errors = 0 for line_ in f: n += 1 if line_[-1] == "\n": line = line_[:-1] else: line = line_ if len(line) <= 0 or line.startswith(additionalservers.COMMENT_STR): continue p = line.split(" ") if len(p) < 2 and needport: debug.msg(additionalservers.DBGTAG_INVALID, "can't fetch server from line %d in file %s" % (n, path)) errors += 1 else: whost = p[0] if len(p) >= 2: try: port = int(p[1]) except: debug.msg(additionalservers.DBGTAG_INVALID, "can't fetch port for server at %s from line %d in file %s" % (whost, n, path)) errors += 1 continue else: port = "*" try: host = socket.gethostbyname(whost) except: debug.msg(additionalservers.DBGTAG_INVALID, "can't resolve host %s for server at %s:%s from line %d in file %s" % (whost, whost, str(port), n, path)) errors += 1 continue item = (host, port) newlist.append(item) addlist.append(item) f.close() dellist = [] for old in oldlist: if addlist.count(old): addlist.remove(old) # was added already else: dellist.append(old) # was removed from file for (synclist, listname) in synclists: for (host, port) in dellist: s = synclist.find(host, port) if s and s.fromfile == path: synclist.removeall(s) debug.msg(additionalservers.DBGTAG_REMOVED, "removed server at %s:%s from %s servers list" % (host, str(port), listname)) for (host, port) in addlist: if add_once: # don't add this anywhere if it already exists in any of the supplied synclists skip = False for (list_, name) in synclists: if list_.find(host, port): skip = True break if skip: debug.msg(additionalservers.DBGTAG_SKIP, "skipping server %s:%s from file %s because it already exists in the supplied synclists" % (host, str(port), path)) continue debug.msg(additionalservers.DBGTAG_ADD, "adding server at %s:%s to %s servers list" % (host, str(port), synclists[0][1])) synclists[0][0].add_from_file(host, (port if (type(port) == types.IntType) else None), file=path) debug.msg(additionalservers.DBGTAG_UPDATED, "updated %d server list%s with servers from file %s: %d items fetched from %d lines, %d errors, %d items added, %d items deleted" % (len(synclists), "s" if len(synclists) > 1 else "", path, len(newlist), n, errors, len(addlist), len(dellist))) return True, "%d items fetched from %d lines, %d errors (skipping lines with errors), %d items added, %d items deleted" % (len(newlist), n, errors, len(addlist), len(dellist)), newlist except: if catch: debug.exc(self) try: f.close() except: pass else: try: f.close() except: pass raise return False, "internal errors occurred", oldlist
def append_once(self, server): if not self.exists(server): if not self._isbanned(server): self._append(server) else: debug.msg(serverlist.DBGTAG_REFUSED, "refused a banned server at %s:%d" % (server.host, server.port))
def onrequest(self, line, addr, build): # return reply, close if line.startswith(masterserver.REGSERV_COMMAND): port = False try: port = int(line[len(masterserver.REGSERV_COMMAND)+1:]) except: debug.msg(masterserver.DBGTAG_INVALID, "could not get port from line received from %s:%d: %s" % (addr+(line,))) return None, False if port < 0 or port > 65534: debug.msg(masterserver.DBGTAG_INVALIDPORT, "server tried to register with invalid port: %d" % port) return ("%s wtf port? %d?" % (masterserver.FAILREG_COMMAND, port)), True debug.msg(masterserver.DBGTAG_REGSERV, "trying to register server at port %d (received from %s:%d)" % ((port,)+addr)) succ, existed, banned = self.regserv(addr[0], port) debug.msg(masterserver.DBGTAG_REGSERV, "registration of %sserver at %s:%d (received from %s:%d) %s%s" % ((("existing " if existed else ""), addr[0], port)+addr+(("succeeded" if succ else "failed"), (", address is banned" if banned else "")))) if succ: return masterserver.SUCCREG_COMMAND, True else: if banned: return ("%s you are banned from this masterserver" % masterserver.FAILREG_COMMAND), True else: return (("%s no reply received after requesting from %s:%d") % (masterserver.FAILREG_COMMAND, addr[0], port+1)), True elif line.startswith(masterserver.SUGGEST_COMMAND): port = False try: addr_s = line[len(masterserver.REGSERV_COMMAND)+1:].split(" ") host_s = addr_s[0] port = int(addr_s[1]) except: debug.msg(masterserver.DBGTAG_INVALID, "could not get host and port from line received from %s:%d: %s" % (addr+(line,))) return ("%s could not parse command, use: %s host port" % (masterserver.FAILREG_COMMAND, masterserver.SUGGEST_COMMAND)), True if port < 0 or port > 65534: debug.msg(masterserver.DBGTAG_INVALIDPORT, "client tried to suggest a server with an invalid port: %d" % port) return ("%s wtf port? %d?" % (masterserver.FAILREG_COMMAND, port)), True try: host = socket.gethostbyname(host_s) except: debug.msg(masterserver.DBGTAG_INVALID, "could not get host and port from line received from %s:%d: %s" % (addr+(line,))) return ("%s could not resolve %s" % (masterserver.FAILREG_COMMAND, host_s)), True debug.msg(masterserver.DBGTAG_SUGGEST, "trying to register suggested server at %s:%d (%s) (received from %s:%d)" % ((host, port, host_s)+addr)) succ, existed, banned = self.suggest(host, port) debug.msg(masterserver.DBGTAG_SUGGEST, "registration of %ssuggested server at %s:%d (received from %s:%d) %s%s" % ((("existing " if existed else ""), host, port)+addr+(("succeeded" if succ else "failed"), (", address is banned" if banned else "")))) if succ: return ("%s the server at %s:%d %s" % (masterserver.SUCCREG_COMMAND, host, port, ("has already been registered" if existed else "is now registered"))), True else: if banned: return ("%s %s:%d is banned from this masterserver" % (masterserver.FAILREG_COMMAND, host, port)), True else: return (("%s server at %s:%d did not reply to info-request (sent to %s:%d)") % (masterserver.FAILREG_COMMAND, host, port, host, port+1)), True return None, False
def processconnection(self, i, funcs): (sock, addr) = i (host, port) = addr debug.msg(netserver.DBGTAG, "connection from %s:%d" % (host, port)) sock.settimeout(2) closecon = False try: while True: lines, err = self.recv(sock) if err: debug.msg(netserver.DBGTAG_RECVFAIL, "an error occured while receiving request from %s:%d" % (host, port)) break for line in lines: if len(line) <= 0: debug.msg(netserver.DBGTAG_EMPTYLINE, "empty line received from %s:%d, skipping" % (host, port)) continue debug.msg(netserver.DBGTAG_TRAFFIC, "received from %s:%d: %s" % (host, port, line)) reply = None close = False cachedreply = self.cache.find(line) build = not bool(cachedreply) for func in funcs: r = func(line, addr, build) if not r: continue (creply, cclose) = r if build: (reply, close) = r if creply or cclose: break if cachedreply: (reply, close) = cachedreply closecon = closecon or close if reply: replytext, n, err = self.send(sock, reply, (debug.tagenabled(netserver.DBGTAG_REPLYTEXT) or ((not cachedreply) and replycache.enabled(line)))) if not err: debug.msg(netserver.DBGTAG_REPLY, "sent %sreply with length %d to %s:%d" % (("cached " if cachedreply else ""), n, host, port)) if replytext != None: debug.msg(netserver.DBGTAG_REPLYTEXT, "sent %sreply to %s:%d: (starts next line)\n%s\n --- end of reply ---" % (("cached " if cachedreply else ""), host, port, replytext)) if (not cachedreply) and replycache.enabled(line): self.cache.cache(line, replytext, close) else: debug.msg(netserver.DBGTAG_SENDFAIL, "an error occured while sending reply to %s:%d" % (host, port)) elif close: # no reply, but close - forceclose debug.msg(netserver.DBGTAG_FORCECLOSE, "force-closing connection to %s:%d without reply" % (host, port)) break else: debug.msg(netserver.DBGTAG_UNKNOWN, "no reply available for line received from %s:%d: %s" % (host, port, line)) if closecon: break except: debug.msg(netserver.DBGTAG, "an error occured while processing connection with %s:%d" % (host, port)) debug.exc() self.accesscache.end(host) shut = False try: sock.shutdown(socket.SHUT_RDWR) shut = True except: pass # remote has already shut down connection try: sock.close() except: pass debug.msg(netserver.DBGTAG, "connection %s:%d closed (shutdown %s)" % (host, port, "succeeded" if shut else "failed"))