class Client(): def __init__(self): self.cManager = QueuedConnectionManager() self.tcpWriter = ConnectionWriter(self.cManager,0) self.tcpReader = QueuedConnectionReader(self.cManager, 0) taskMgr.add(self.tskReaderPolling,"Poll the connection reader",-40) # This fails self.conn = self.cManager.openTCPClientConnection(IP_ADDR, PORT, 1000) if self.conn: print 'Successful connection to', IP_ADDR, ':', PORT self.tcpReader.addConnection(self.conn) self.SendPacket() def SendPacket(self): dg = PyDatagram() dg.addUint8(5) self.tcpWriter.send(dg, self.conn) def tskReaderPolling(self, task): if self.tcpReader.dataAvailable(): datagram = NetDatagram() if self.tcpReader.getData(datagram): print 'client got data' return task.cont
class Client(DirectObject): def __init__(self): self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.connection = None #Connection with the server def connectToServer(self, ip_address="192.168.1.110", port_address=9099): #How long to wait until we give up connecting timeout = 3000 # 3 seconds self.connection = self.cManager.openTCPClientConnection(ip_address,port_address,timeout) if self.connection: self.cReader.addConnection(self.connection) #Retrieve message from Server return True #We connected return False #We couldn't succeed def processMsgData(self, dataGram): iterator = PyDatagramIterator(dataGram) msgID = iterator.getUint8() if msgID == PRINT_MESSAGE: msg = iterator.getString() print msg def recieveMessage(self): datagram = NetDatagram() #Needed to store the message or data recieved if self.cReader.getData(datagram): self.processMsgData(datagram) ''' Closes the connection with the server ''' def disconnectServer(self): self.cManager.closeConnection(self.connection)
class Client(DirectObject): def __init__( self ): print "Initializing client test" self.port = 9099 self.ip_address = "142.157.150.72" self.timeout = 3000 # 3 seconds to timeout self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.Connection = self.cManager.openTCPClientConnection(self.ip_address, self.port, self.timeout) if self.Connection: taskMgr.add(self.tskReaderPolling,"read the connection listener",-40) # this tells the client to listen for datagrams sent by the server print "Connected to Server" self.cReader.addConnection(self.Connection) PRINT_MESSAGE = 1 myPyDatagram = PyDatagram() myPyDatagram.addUint8(100) # adds an unsigned integer to your datagram myPyDatagram.addString("first string of text") # adds a string to your datagram myPyDatagram.addString("second string of text") # adds a second string to your datagram self.cWriter.send(myPyDatagram, self.Connection) # fires it off to the server #self.cManager.closeConnection(self.Connection) #print "Disconnected from Server" # uncomment the above 2 lines if you want the client to # automatically disconnect. Or you can just # hit CTRL-C twice when it's running to kill it # in windows, I don't know how to kill it in linux else: print "Not connected to Server" def tskReaderPolling(self, task): if self.cReader.dataAvailable(): datagram=PyDatagram() if self.cReader.getData(datagram): self.processServerMessage(datagram) return Task.cont def processServerMessage(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) print myIterator.getString()
class Server(): def __init__(self): self.cManager = QueuedConnectionManager() self.tcpSocket = self.cManager.openTCPServerRendezvous(PORT, 1000) self.tcpWriter = ConnectionWriter(self.cManager,0) self.tcpListener = QueuedConnectionListener(self.cManager, 0) self.tcpListener.addConnection(self.tcpSocket) self.tcpReader = QueuedConnectionReader(self.cManager, 0) taskMgr.add(self.tskListenerPolling,"Poll the connection listener",-39) taskMgr.add(self.tskReaderPolling,"Poll the connection reader",-40) def SendPacket(self): dg = PyDatagram() dg.addUint8(5) self.tcpWriter.send(dg, self.conn) def tskReaderPolling(self, task): if self.tcpReader.dataAvailable(): datagram = NetDatagram() if self.tcpReader.getData(datagram): print 'server got data' self.SendPacket() return task.cont def tskListenerPolling(self, task): if self.tcpListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.tcpListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.tcpReader.addConnection(newConnection) self.conn = newConnection print self.conn.getAddress().getPort() return task.cont
class Client: def __init__(self, showbase, host, port, timeout=3000, compress=False): self.showbase = showbase self.host = host self.port = port self.timeout = timeout self.compress = compress self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) # By default, we are not connected self.connected = False self.passedData = [] self.connect(self.host, self.port, self.timeout) self.startPolling() def startPolling(self): self.showbase.taskMgr.add(self.tskDisconnectPolling, "clientDisconnectTask", -39) def connect(self, host, port, timeout=3000): # Connect to our host's socket self.myConnection = self.cManager.openTCPClientConnection( host, port, timeout) if self.myConnection: self.cReader.addConnection( self.myConnection) # receive messages from server self.connected = True # Let us know that we're connected def getConnected(self): # Check whether we are connected or not return self.connected def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable() == True: connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) # Let us know that we are not connected self.connected = False return Task.cont def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def encode(self, data, compress=False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, self.myConnection) def passData(self, data): self.passedData.append(data) def getData(self): data = [] for passed in self.passedData: data.append(passed) self.passedData.remove(passed) while self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): data.append(self.processData(datagram)) return data
class LoginServer: def __init__(self, port, backlog=1000, compress=False): self.port = port self.backlog = backlog self.compress = compress self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.db = DataBase() # This is for pre-login self.tempConnections = [] # This is for authed clients self.activeConnections = [] # Temp user dict self.clients={} self.connect(self.port, self.backlog) self.startPolling() def connect(self, port, backlog=1000): # Bind to our socket tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(tcpSocket) def startPolling(self): taskMgr.add(self.tskListenerPolling, "serverListenTask", -40) taskMgr.add(self.tskDisconnectPolling, "serverDisconnectTask", -39) def tskListenerPolling(self, task): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.tempConnections.append(newConnection) # Lets add it to a temp list first. self.cReader.addConnection(newConnection) # Begin reading connection # Make the temp place holder then add to temp, under dataget check the temp list, if something ther do # auth and then add to the active return Task.cont def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable() == True: print "disconnect" connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) for u in range(len(self.clients)): if self.clients[u]['connection']==connection: del self.clients[u] break # Loop through the activeConnections till we find the connection we just deleted # and remove it from our activeConnections list for c in range(0, len(self.activeConnections)): if self.activeConnections[c] == connection: del self.activeConnections[c] break return Task.cont def broadcastData(self, data): # Broadcast data out to all activeConnections for con in self.activeConnections: self.sendData(data, con) def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def getClients(self): # return a list of all activeConnections return self.activeConnections def encode(self, data, compress=False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data, con): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, con) # This will check and do the logins. def auth(self, datagram): # If in login state. clientIp = datagram.getAddress() # This is the ip :P clientCon = datagram.getConnection() # This is the connection data. used to send the shit. package=self.processData(datagram) print "SERVER: ",package valid_packet=False if len(package)==2: # if login request is send reply # Should add a checker like in the db something like isLogged(0 or 1) # If found then say no for client user_found=False if package[0]=='login_request': valid_packet=True print "Try login" for u in range(len(self.clients)): if self.clients[u]['name']==package[1][0]: print "User already exists" user_found=True data = {} data[0] = "error" data[1] = "User already logged in" self.sendData(data,clientCon) break # send something back to the client saying to change username if not user_found: username=package[1][0] password=package[1][1] self.db.Client_getLogin(username, password) if self.db.login_valid: # Add the user new_user={} new_user['name']=package[1][0] new_user['connection']=clientCon new_user['ready']=False new_user['new_dest']=False new_user['new_spell']=False self.clients[len(self.clients)]=new_user # Send back the valid check. data={} data[0]='login_valid' # If client gets this the client should switch to main_menu. data[1]={} data[1][0]=self.db.status data[1][1]=len(self.clients)-1 # This is part of the old 'which' packet self.sendData(data, clientCon) # Move client to the self.activeConnections list. self.activeConnections.append(clientCon) print "HERE IS ACTIVE: ", self.activeConnections self.tempConnections.remove(clientCon) print "HERE IS TEMP", self.tempConnections else: status = self.db.status data={} data[0]='db_reply' data[1]=status self.sendData(data, clientCon) if not valid_packet: data = {} data[0] = "error" data[1] = "Wrong Packet" self.sendData(data, clientCon) print "Login Packet not correct" else: print "Data in packet wrong size" def getData(self): data = [] while self.cReader.dataAvailable(): datagram = NetDatagram() # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self.cReader.getData(datagram): if datagram.getConnection() in self.tempConnections: print "Check Auth!" self.auth(datagram) print "Auth Done!" # in auth def or after the connection will be moved to self.activeConnections # and then removed from the temp list break # Check if the data rechieved is from a valid client. elif datagram.getConnection() in self.activeConnections: appendage={} appendage[0]=self.processData(datagram) appendage[1]=datagram.getConnection() data.append(appendage) return data
class Client: def __init__(self, host, port, timeout=3000, compress=False): self.host = host self.port = port self.timeout = timeout self.compress = compress self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) # By default, we are not connected self.connected = False self.connect(self.host, self.port, self.timeout) self.startPolling() def connect(self, host, port, timeout=3000): # Connect to our host's socket self.myConnection = self.cManager.openTCPClientConnection(host, port, timeout) if self.myConnection: self.cReader.addConnection(self.myConnection) # receive messages from server self.connected = True # Let us know that we're connected def startPolling(self): taskMgr.add(self.tskDisconnectPolling, "clientDisconnectTask", -39) def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable() == True: connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) # Let us know that we are not connected self.connected = False return Task.cont def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def getConnected(self): # Check whether we are connected or not return self.connected def encode(self, data, compress=False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, self.myConnection) def getData(self): data = [] while self.cReader.dataAvailable(): datagram = NetDatagram() # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self.cReader.getData(datagram): data.append(self.processData(datagram)) return data
class SocketServer(): def __init__(self, port, virtual_world, camera_mgr, sync_session): self.port = port self.virtual_world = virtual_world self.cam_mgr = camera_mgr self.task_mgr = virtual_world.taskMgr self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cReader.setRawMode(True) self.cWriter = ConnectionWriter(self.cManager, 1) self.cWriter.setRawMode(True) self.tcpSocket = self.cManager.openTCPServerRendezvous(port, BACKLOG) self.cListener.addConnection(self.tcpSocket) self.activeSessions = {} self.connection_map = {} self.set_handlers() hostname = socket.gethostname() a, b, address_list = socket.gethostbyname_ex(hostname) self.ip = address_list[0] logging.info("Addresses %s" % address_list) logging.info("Server is running on ip: %s, port: %s" %(self.ip, self.port)) self.client_counter = 0 self.read_buffer = '' self.read_state = 0 self.read_body_length = 0 self.packet = SocketPacket() controller = virtual_world.getController() self.sync = Sync(self.task_mgr, controller, camera_mgr, sync_session) self.vv_id = None if sync_session: logging.info("Waiting for Sync Client!") self.showing_info = False virtual_world.accept("i", self.toggleInfo) self.sync_session = sync_session self.createInfoLabel() atexit.register(self.exit) def createInfoLabel(self): string = self.generateInfoString() self.info_label = OST(string, pos=(-1.3, -0.5), fg=(1,1,1,1), bg=(0,0,0,0.7), scale=0.05, align=TextNode.ALeft) self.info_label.hide() def generateInfoString(self,): string = " IP:\t%s \n" % self.ip string += " PORT:\t%s \n" % self.port if self.sync_session: string += " MODE:\tSync Client\n" string += " VV ID:\t%s\n" % self.vv_id else: string += " MODE:\tAutomatic\n" cameras = self.cam_mgr.getCameras() num_cameras = len(cameras) for camera in cameras: id = camera.getId() type = camera.getTypeString() string += " Cam%s:\t%s\n" %(id, type) string += "\n" return string def set_handlers(self): self.task_mgr.add(self.connection_polling, "Poll new connections", -39) self.task_mgr.add(self.reader_polling, "Poll reader", -40) self.task_mgr.add(self.disconnection_polling, "PollDisconnections", -41) def connection_polling(self, taskdata): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConn = PointerToConnection() if self.cListener.getNewConnection(rendezvous,netAddress, newConn): conn = newConn.p() self.cReader.addConnection(conn) # Begin reading connection conn_id = self.client_counter logging.info("New Connection from ip:%s, conn:%s" % (conn.getAddress(), conn_id)) self.connection_map[conn_id] = conn self.client_counter += 1 message = eVV_ACK_OK(self.ip, self.port, conn_id) self.sendMessage(message, conn) return Task.cont def reader_polling(self, taskdata): if self.cReader.dataAvailable(): datagram = NetDatagram() # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self.cReader.getData(datagram): self.read_buffer = self.read_buffer + datagram.getMessage() while (True): if self.read_state == 0: if len(self.read_buffer) >= self.packet.header_length: bytes_consumed = self.packet.header_length self.packet.header = self.read_buffer[:bytes_consumed] self.read_body_length = self.packet.decode_header() self.read_buffer = self.read_buffer[bytes_consumed:] self.read_state = 1 else: break if self.read_state == 1: if len(self.read_buffer) >= self.read_body_length: bytes_consumed = self.read_body_length self.packet.data = self.read_buffer[:bytes_consumed] self.packet.offset = 0 self.read_body_length = 0 self.read_buffer = self.read_buffer[bytes_consumed:] self.read_state = 0 self.new_data_callback(self.packet) else: break return Task.cont def new_data_callback(self, packet): packet = copy.deepcopy(packet) message_type = packet.get_int() conn_id = packet.get_int() if message_type == VP_SESSION: conn = self.connection_map[conn_id] type = packet.get_char() pipeline = packet.get_char() req_cam_id = packet.get_int() logging.debug("Received VP_SESSION message from conn:%s, " \ "type=%s, pipeline=%s requested camera id=%d" %(conn_id, VP_TYPE[type], PIPELINE[pipeline], req_cam_id)) self.newVPSession(conn, type, pipeline, conn_id, req_cam_id) elif message_type == SYNC_SESSION: vv_id = packet.get_int() self.vv_id = vv_id string = self.generateInfoString() self.info_label.setText(string) conn = self.connection_map[conn_id] logging.debug("Received SYNC_SESSION message from conn:%s" %conn_id) self.newSyncSession(conn, conn_id, vv_id) logging.info("Sync client connected") elif message_type == VP_REQ_CAM_LIST: logging.debug("Received VP_REQ_CAM_LIST message from conn:%s" % conn_id) cameras = self.cam_mgr.getCameras() pipeline = self.activeSessions[conn_id].getPipeline() camera_type = None if pipeline == STATIC_PIPELINE: camera_type = VP_STATIC_CAMERA elif pipeline == PTZ_PIPELINE: camera_type = VP_ACTIVE_CAMERA cam_list = [] for camera in cameras: if camera_type == camera.getType() and not camera.hasSession(): cam_list.append(camera.getId()) message = eVV_CAM_LIST(self.ip, self.port, cam_list) conn = self.connection_map[conn_id] logging.debug("Sent VV_CAM_LIST message to conn:%s" % conn_id) self.sendMessage(message, conn) elif message_type == VP_REQ_IMG: cam_id = packet.get_int() frequency = packet.get_char() width = packet.get_int() height = packet.get_int() jpeg = packet.get_bool() data = (frequency, width, height, jpeg) camera = self.cam_mgr.getCameraById(cam_id) logging.debug("Received VV_REQ_IMG message from conn:%s" % conn_id) if camera and not camera.hasSession(): session = self.activeSessions[conn_id] session.addCamera(cam_id) camera.setSession(session, VP_BASIC, self.ip, self.port, data) else: if conn_id in self.activeSessions: self.activeSessions[conn_id].newMessage(message_type, packet) def newVPSession(self, conn, type, pipeline, conn_id, req_cam_id): if type == VP_ADVANCED: camera_type = -1 if pipeline == STATIC_PIPELINE: camera_type = STATIC_CAMERA ## Change this to use a different static camera class elif pipeline == PTZ_PIPELINE: camera_type = ACTIVE_CAMERA if camera_type != -1: #cam = self.cam_mgr.getAvailableCamera(camera_type) cam = self.cam_mgr.getRequestedCamera(camera_type, req_cam_id) if cam: session = VPSession(conn_id, conn, self, VP, pipeline) session.addCamera(cam.getId()) self.activeSessions[conn_id] = session message = eVV_VP_ACK_OK(self.ip, self.port, cam.getId()) logging.debug("Sent VV_VP_ACK_OK message to conn:%s" % conn_id) self.sendMessage(message, conn) cam.setSession(session, type, self.ip, self.port) else: message = eVV_VP_ACK_FAILED(self.ip, self.port) logging.debug("Sent VV_VP_ACK_FAILED message to conn:%s" % conn_id) self.sendMessage(message, conn) else: message = eVV_VP_ACK_FAILED(self.ip, self.port) logging.debug("Sent VV_VP_ACK_FAILED message to conn:%s" % conn_id) self.sendMessage(message, conn) def newSyncSession(self, conn, conn_id, vv_id): session = SyncSession(conn_id, conn, self, SYNC) self.sync.setSession(session, vv_id, self.ip, self.port) self.activeSessions[conn_id] = session message = eVV_SYNC_ACK(self.ip, self.port, vv_id) logging.debug("Sent VV_SYNC_ACK message to conn:%s" % conn_id) self.sendMessage(message, conn) def sendMessage(self, message, conn): self.cWriter.send(message, conn) def disconnection_polling(self, taskdata): if(self.cManager.resetConnectionAvailable()): connectionPointer = PointerToConnection() self.cManager.getResetConnection(connectionPointer) lostConnection = connectionPointer.p() for session in self.activeSessions.values(): if session.conn == lostConnection: logging.info("Lost Connection from ip:%s, conn:%s" %(session.client_address, session.conn_id)) conn_id = session.conn_id if session.getSessionType() == VP: cameras = session.getCameras() for cam_id in cameras: camera = self.cam_mgr.getCameraById(cam_id) camera.clearSession() del self.activeSessions[conn_id] del self.connection_map[conn_id] break self.cManager.closeConnection(lostConnection) return Task.cont def toggleInfo(self): if self.showing_info: self.info_label.hide() self.showing_info = False else: self.info_label.show() self.showing_info = True def exit(self): for connection in self.connection_map.values(): self.cReader.removeConnection(connection) self.cManager.closeConnection(self.tcpSocket) self.tcpSocket.getSocket().Close()
class Server(DirectObject): def __init__( self ): self.port = 9099 self.portStatus = "Closed" self.host = "localhost" self.backlog = 1000 self.Connections = {} # basic configuration variables that are used by most of the # other functions in this class self.StartConnectionManager() # manages the connection manager self.DisplayServerStatus() # output a status box to the console which tells you the port # and any connections currently connected to your server def DisplayServerStatusTASK(self, task): # all this does is periodically load the status function below # add a task to display it every 30 seconds while you are doing # any new coding self.DisplayServerStatus() return Task.again def DisplayServerStatus(self): print "\n----------------------------------------------------------------------------\n" print "SERVER STATUS:\n\n" print "Connection Manager Port: " + str(self.port) + " [" + str(self.portStatus) + "]" for k, v in self.Connections.iteritems(): print "Connection " + k ################################################################## # TCP Networking Functions and Tasks ################################################################## def StartConnectionManager(self): # this function creates a connection manager, and then # creates a bunch of tasks to handle connections # that connect to the server self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.tcpSocket = self.cManager.openTCPServerRendezvous(self.port,self.backlog) self.cListener.addConnection(self.tcpSocket) self.portStatus = "Open" taskMgr.add(self.ConnectionManagerTASK_Listen_For_Connections,"Listening for Connections",-39) # This task listens for new connections taskMgr.add(self.ConnectionManagerTASK_Listen_For_Datagrams,"Listening for Datagrams",-40) # This task listens for new datagrams taskMgr.add(self.ConnectionManagerTASK_Check_For_Dropped_Connections,"Listening for Disconnections",-41) # This task listens for disconnections def ConnectionManagerTASK_Listen_For_Connections(self, task): if(self.portStatus == "Open"): # This exists in case you want to add a feature to disable your # login server for some reason. You can just put code in somewhere # to set portStatus = 'closed' and your server will not # accept any new connections if self.cListener.newConnectionAvailable(): print "CONNECTION" rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous,netAddress,newConnection): newConnection = newConnection.p() self.Connections[str(newConnection.this)] = rendezvous # all connections are stored in the self.Connections # dictionary, which you can use as a way to assign # unique identifiers to each connection, making # it easy to send messages out self.cReader.addConnection(newConnection) print "\nSOMEBODY CONNECTED" print "IP Address: " + str(newConnection.getAddress()) print "Connection ID: " + str(newConnection.this) print "\n" # you can delete this, I've left it in for debugging # purposes self.DisplayServerStatus() # this fucntion just outputs the port and # current connections, useful for debugging purposes return Task.cont def ConnectionManagerTASK_Listen_For_Datagrams(self, task): if self.cReader.dataAvailable(): datagram=NetDatagram() if self.cReader.getData(datagram): print "\nDatagram received, sending response" myResponse = PyDatagram() myResponse.addString("GOT YER MESSAGE") self.cWriter.send(myResponse, datagram.getConnection()) # this was just testing some code, but the server will # automatically return a 'GOT YER MESSAGE' datagram # to any connection that sends a datagram to it # this is where you add a processing function here #myProcessDataFunction(datagram) return Task.cont def ConnectionManagerTASK_Check_For_Dropped_Connections(self, task): # if a connection has disappeared, this just does some house # keeping to officially close the connection on the server, # if you don't have this task the server will lose track # of how many people are actually connected to you if(self.cManager.resetConnectionAvailable()): connectionPointer = PointerToConnection() self.cManager.getResetConnection(connectionPointer) lostConnection = connectionPointer.p() # the above pulls information on the connection that was lost print "\nSOMEBODY DISCONNECTED" print "IP Address: " + str(lostConnection.getAddress()) print "ConnectionID: " + str(lostConnection.this) print "\n" del self.Connections[str(lostConnection.this)] # remove the connection from the dictionary self.cManager.closeConnection(lostConnection) # kills the connection on the server self.DisplayServerStatus() return Task.cont
class UDPconnection(): """ base class for UDP server and client, handles basic communication (decoding/encoding), buffering and resending """ def __init__(self, port='9099', timeout=3.0, commTicks=50, resendTime=0.33, reliable=0, concurrent=10, maxlength=480): self.logger = logging.getLogger('UDPcon') self.port = port # Start the UDP Connection self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.conn = self.cManager.openUDPConnection(self.port) self.cReader.addConnection(self.conn) self.handlers = {} self.nextID = 1 self.commBuffer = [] self.conAddresses = [] self.conIDs = [] self.timeout = timeout self.commTicks = commTicks self.commTime = 1.0 / self.commTicks self.time = ClockObject() self.resendTime = resendTime self.reliable = reliable self.concurrent = concurrent self.maxlength = maxlength self.multMsgID = 0 # receive data # taskMgr.add(self.listendata, "Incoming Data Listener", -40) self.running = True self.threadLock = threading.Lock() self.listenThread = threading.Thread(target=self.listendata) self.batchThread = threading.Thread(target=self.batch) for thread in [self.listenThread, self.batchThread]: thread.daemon = True thread.start() self.handlers[KEEP_ALIVE] = self.reply self.handlers[CONFIRM] = self.sync # logging.debug('UDPconnection created') self.logger.debug('UDPconnection created') def batch(self): # recurring tasks while self.running: self.threadLock.acquire() self.timenow = self.time.getFrameTime() self.sendDataBuffer() self.chkCommBuffers() self.threadLock.release() time.sleep(self.commTime) def listendata(self): # function that listens for incoming data, updating communication clock and calling handler-functions, should be added to taskMgr time.sleep(0.02) while self.running: time.sleep(0.005) # time.sleep(0.1) self.time.tick() data = self.getData() if data: self.threadLock.acquire() self.timenow = self.time.getFrameTime() # we only accept authentication requests from not-connected remote machines, all other incomming data is discarded for d in data: # print "incoming: ", d[MSG_TYPE], d[SEQN] if d[MSG_TYPE] == CMSG_AUTH or d[MSG_TYPE] == SMSG_AUTH_RESPONSE: # if d[MSG_TYPE] == CMSG_AUTH: if d[MSG_TYPE] in self.handlers: self.handlers[d[MSG_TYPE]](d[DATA], d[ADDR]) continue ind = self.getCommBufferByAddr(d[ADDR]) if ind < 0: continue self.commBuffer[ind].lastRecv = self.timenow # remove confirmed messages self.commBuffer[ind].confirm(d[AKN], time=self.timenow) if d[MSG_TYPE] == MULT: if d[SEQN] > 0 and d[SEQN] <= self.commBuffer[ind].rseqNumber: continue d = self.commBuffer[ind].addPartialMsg(d, time=self.timenow) else: if d[OAKN]: self.commBuffer[ind].remove(d[OAKN]) # discard message if already received if d[SEQN] > 0 and d[SEQN] <= self.commBuffer[ind].rseqNumber: continue execute = [] # unreliable messages are always executed when they are received without sending a confirmation if d[SEQN] < 0: execute = [d] else: # if received message is the next in line or can be executed out of line -> execute=1, otherwise store in recvBuffer if d[SEQN] == self.commBuffer[ind].rseqNumber + 1: self.commBuffer[ind].rseqNumber += 1 execute = [d] else: if d[OOL]: execute = [d] self.commBuffer[ind].addRecvMessage(d, recvtime=self.timenow) # look for messages that are now in line to be processed for msg in self.commBuffer[ind].getRecvBuffer(): if not msg[OOL]: execute.append(msg) # call handler and pass data to it for msg in execute: if msg[MSG_TYPE] in self.handlers and not msg[MSG_TYPE] == MULT: try: self.handlers[msg[MSG_TYPE]](msg[DATA], id=self.commBuffer[ind].id) except: self.handlers[msg[MSG_TYPE]](msg[DATA]) self.threadLock.release() def chkCommBuffers(self): for cb in self.commBuffer: for msg in cb.incompleteRecvBuffer[:]: if msg['lastupdate'] and (self.timenow - msg['lastupdate']) > self.timeout: cb.incompleteRecvBuffer.remove(msg) # timeout not yet fully implemented return remove = [] for cb in self.commBuffer: if (self.time.getFrameTime() - cb.lastRecv) > self.timeout: remove.append(cb.id) for id in remove: ind = self.getCommBufferByID(id) del self.commBuffer[ind] def getCommBufferByAddr(self, addr): # self.conAddresses = [(cb.addr.getIp(), cb.addr.getPort()) for cb in self.commBuffer] try: ind = self.conAddresses.index((addr.getIp(), addr.getPort())) except ValueError: ind = -1 return ind def getCommBufferByID(self, id): # print type(self.commBuffer) # self.conIDs = [cb.id for cb in self.commBuffer] try: ind = self.conIDs.index(id) except ValueError: ind = -1 return ind def encode(self, data): # encode the data with rencode # return rencode.dumps(data) return rencode.dumps(data) def decode(self, data): # decode the data with rencode # return rencode.loads(data) return rencode.loads(data) def sync(self, data, id=None): if id is not None: ind = self.getCommBufferByID(id) if abs(data[0] - self.commBuffer[ind].lastKeepAlive) > 1.e-3: ping = self.time.getFrameTime() - data[0] self.commBuffer[ind].addping(ping, time=self.timenow) def reply(self, data, id=None): if id is not None: data = [data, self.time.getFrameTime()] self.sendDataToID(data, id, msgtype=CONFIRM, reliable=False) def sendDataBuffer(self): # all messages that haven't been confirmed in ping + sigma(ping) will be resend for buff in self.commBuffer: addr = buff.addr # timenow = self.time.getFrameTime() timenow = self.timenow sent = 0 for msg in buff.sendBuffer: oakn = [m[SEQN] for m in buff.recvBuffer] if len(oakn) > 5: oakn = oakn[0:4] oakn_encoded = self.encode(oakn) if self.time.getFrameTime() - msg[TIME] > buff.ping: # self.sendData(msg['data'], addr, msgtype=msg['msgtype'], seqNum=msg['sqn'], encode=False) msg[AKN] = buff.rseqNumber if not msg[MSG_TYPE] == MULT: if msg[ENCODED]: msg[OAKN] = oakn_encoded else: msg[OAKN] = oakn buff.lastAKN = msg[AKN] self.sendMessage(msg, addr) msg[TIME] = self.time.getFrameTime() sent += 1 if sent >= self.concurrent: break if timenow - buff.lastRecv > self.resendTime or buff.lastAKN < buff.rseqNumber or timenow - buff.lastPingAdded > 1.0: # self.sendDataToID("", buff.id, msgtype=KEEP_ALIVE, out_of_line=True) buff.lastKeepAlive = timenow self.sendDataToID(timenow, buff.id, msgtype=KEEP_ALIVE, reliable=False) def sendMessage(self, msg, addr): # print "sending!: ", msg, addr.getIpString(), addr.getPort() myPyDatagram = self._crDatagram(msg) # print "size: ", sys.getsizeof(myPyDatagram), "type: ", msg[MSG_TYPE], "data: ", msg[DATA] self.cWriter.send(myPyDatagram, self.conn, addr) def sendDataToID(self, data, cID, reliable=None, **kwargs): msg = self._crMessage(data, **kwargs) ind = self.getCommBufferByID(cID) if ind < 0: raise IndexError self._sendMessageToIndex(msg, ind, reliable=reliable) def broadcast(self, data, reliable=None, **kwargs): msg = self._crMessage(data, **kwargs) for ind in xrange(len(self.commBuffer)): self._sendMessageToIndex(msg, ind, reliable=reliable) def _sendDataToIndex(self, data, index, reliable=None, **kwargs): msg = self._crMessage(data, **kwargs) # print "sending msg: ", msg self._sendMessageToIndex(msg, index, reliable=reliable) def _sendMessageToIndex(self, message, index, reliable=None): if not isinstance(index, collections.Iterable): index = [index] if type(message)==dict: message = [message] for msg in message: for ind in index: if reliable is None: reliable = self.reliable if not reliable: msg[SEQN] = -1 else: msg[SEQN] = self.commBuffer[ind].addSendMessage(msg, sendtime=self.time.getFrameTime()) msg[AKN] = self.commBuffer[ind].rseqNumber if not msg[MSG_TYPE] == MULT: if msg[ENCODED]: msg[OAKN] = self.encode([m[SEQN] for m in self.commBuffer[ind].recvBuffer]) else: msg[OAKN] = [m[SEQN] for m in self.commBuffer[ind].recvBuffer] # print "sending to: ", self.commBuffer[ind].id, self.commBuffer[ind].addr.getIpString(), self.commBuffer[ind].addr.getPort() self.commBuffer[ind].lastSend = self.time.getFrameTime() self.commBuffer[ind].lastAKN = msg[AKN] self.sendMessage(msg, self.commBuffer[ind].addr) def sendData(self, data, addr, **kwargs): msg = self._crMessage(data, **kwargs) if not isinstance(addr, collections.Iterable): addr = [addr] if type(msg)==dict: msg = [msg] for address in addr: for m in msg: self.sendMessage(m, address) def _crMessage(self, data, msgtype=0, seqNum=-1, akn=0, oakn={}, out_of_line=False): enc_data = self.encode(data) if len(enc_data) > self.maxlength: chunks = self.chunks(enc_data, self.maxlength) nchunks = math.ceil(len(enc_data) / (1.0 * self.maxlength)) identifier = self.multMsgID self.multMsgID += 1 oakn = [msgtype, identifier, nchunks] msgtype = MULT else: chunks = [enc_data] nchunks = 1 messages = [] n = 0 for dat in chunks: msg = {} msg[SEQN] = seqNum msg[AKN] = akn msg[MSG_TYPE] = msgtype msg[OOL] = out_of_line if nchunks > 1: oakn.append(n) msg[OAKN] = self.encode(oakn) oakn.pop() n += 1 else: msg[OAKN] = self.encode(oakn) msg[DATA] = dat msg[ENCODED] = True msg[ADDR] = None msg[TIME] = 0 messages.append(msg) return messages def _crDatagram(self, msg): # create Datagram from message myPyDatagram = PyDatagram() myPyDatagram.addInt32(msg[SEQN]) myPyDatagram.addInt32(msg[AKN]) myPyDatagram.addInt16(msg[MSG_TYPE]) myPyDatagram.addInt8(msg[OOL]) if not msg[ENCODED]: myPyDatagram.addString(self.encode(msg[OAKN])) myPyDatagram.addString(self.encode(msg[DATA])) else: myPyDatagram.addString(msg[OAKN]) myPyDatagram.addString(msg[DATA]) return myPyDatagram def _processData(self, netDatagram): # convert incoming Datagram to dict myIterator = PyDatagramIterator(netDatagram) msg = {} msg[SEQN] = myIterator.getInt32() msg[AKN] = myIterator.getInt32() msg[MSG_TYPE] = myIterator.getInt16() msg[OOL] = myIterator.getInt8() msg[OAKN] = self.decode(myIterator.getString()) if not msg[MSG_TYPE] == MULT: msg[DATA] = self.decode(myIterator.getString()) else: msg[DATA] = (myIterator.getString()) # msg.append(self.decode(myIterator.getString())) return msg def getData(self): data = [] while self.cReader.dataAvailable(): datagram = NetDatagram() # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self.cReader.getData(datagram): # pkg = [] pkg = self._processData(datagram) tmpaddr = datagram.getAddress() addr = NetAddress() addr.setHost(tmpaddr.getIpString(), tmpaddr.getPort()) pkg[ADDR] = addr data.append(pkg) return data def addCommBuffer(self, addr): cb_id = self.nextID self.commBuffer.append(commBuffer(id=cb_id, addr=addr, lastRecv=self.time.getFrameTime())) self.nextID += 1 self.conAddresses = [(cb.addr.getIp(), cb.addr.getPort()) for cb in self.commBuffer] self.conIDs = [cb.id for cb in self.commBuffer] return cb_id def removeCommBuffer(self, cID): ind = self.getCommBufferByID(cID) if ind < 0: raise IndexError del self.commBuffer[ind] self.conAddresses = [(cb.addr.getIp(), cb.addr.getPort()) for cb in self.commBuffer] self.conIDs = [cb.id for cb in self.commBuffer] def chunks(self, string, n): return [string[i:i+n] for i in range(0, len(string), n)]
class PSGServer(object): ''' The main server that listens for connections and manages active games. This also runs the console which can interact with the server.''' # registeredUsers is a list of User objects of registered users registeredUsers = [] # connectedUsers is a list of User objects of currently connected users connectedUsers = [] # connections is a list of Connection objects connections =[] # Connections that have not responded to their keepalive request. # A dictionary of the form (Connection, pingtime) pingNonResponders = {} # games is a list of active GameStateServer objects games = [] def __init__(self): ''' Initialize the server.''' import __builtin__ __builtin__.LOG = LogConsole() print('Starting PSG Server ...') self._cManager = QueuedConnectionManager() self._cListener = QueuedConnectionListener(self._cManager, 0) self._cReader = QueuedConnectionReader(self._cManager, 0) self._cWriter = ConnectionWriter(self._cManager,0) #TODO - Load user file (DB) self.registeredUsers =[ServerPlayer('chad','password1'), ServerPlayer('josh','password2'), ServerPlayer('james','password3')] # Map store self._mapStore = MapStore() # Open socket self._tcpSocket = self._cManager.openTCPServerRendezvous(PORT,BACKLOG) self._cListener.addConnection(self._tcpSocket) # Setup interfaces self._console = InterfaceConsole(self) # Setup system tasks taskMgr.add(self.__listenTask, 'serverListenTask', -40) taskMgr.add(self.__readTask, 'serverReadTask', -39) taskMgr.doMethodLater(PING_DELAY, self.__pingTask, 'serverPingTask', sort=-41) taskMgr.doMethodLater(1, self.__checkPingRespTask, 'serverCheckPingRespTask', sort=-10) print('Server initialized') def __listenTask(self, Task): ''' This task listens for connections. When a connection is made it adds the connection to the clients list and begins listening to that connection.''' if self._cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self._cListener.getNewConnection(rendezvous,netAddress,newConnection): newConnection = newConnection.p() if newConnection not in self.connections: self.connections.append(newConnection) self._cReader.addConnection(newConnection) # Begin reading connection self._console.printNotice('Connection from %s'%netAddress.getIpString()) else: self._console.printNotice('%s: already connected'%(newConnection.getAddress().getIpString())) return Task.cont def __readTask(self, Task): ''' This task listens for any messages coming in over any connections. If we get a connection passes it to the datagram handler.''' if self._cReader.dataAvailable(): datagram=NetDatagram() if self._cReader.getData(datagram): data = PyDatagramIterator(datagram) msgID = data.getUint16() else: data = None msgID = MSG_NONE else: datagram = None data = None msgID = MSG_NONE if msgID is not MSG_NONE: self.__handleDatagram(data, msgID, datagram.getConnection()) return Task.cont def __pingTask(self, Task): ''' Ping all clients every PING_DELAY seconds to check for those who have dropped their connection.''' notice = 'Pinging: ' for c in self.connections: # Don't ping connections we're still waiting on if c not in self.pingNonResponders.keys(): notice = '%s%s '%(notice, c.getAddress().getIpString()) self.pingNonResponders[c] = int(time.time()) pkg = NetDatagram() pkg.addUint16(MSG_PING_REQ) self._cWriter.send(pkg, c) LOG.notice(notice) # Add task back into the taskmanager taskMgr.doMethodLater(PING_DELAY, self.__pingTask, 'serverPingTask', sort=-41) def __checkPingRespTask(self, Task): ''' Run through the list of connections that haven't responded to their ping yet and disconnect them if has been more than PING_TIMEOUT seconds.''' notice = 'Cleaning non-responders ' for c in self.pingNonResponders.keys(): notice = '%s%s '%(notice, c.getAddress().getIpString()) now = int(time.time()) pingTime = self.pingNonResponders[c] if ((now - pingTime) > PING_TIMEOUT): #print('disconnecting '), self.__handleDisconnect(None, None, c) LOG.notice(notice) # Add task back into the taskmanager taskMgr.doMethodLater(1, self.__checkPingRespTask, 'serverCheckPingRespTask', sort=-10) def __handleDatagram(self, data, msgID, client): ''' This handles incoming messages. It can run the appropriate handler from the server or pass it to the relevant game to deal with. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' self._console.printNotice('%s: Recieved msg: %d'%(client.getAddress().getIpString(),msgID)) # System messages if (msgID == MSG_PING_REQ): self._console.printNotice('Notice: MSG_PING_REQ') self.__handlePingReq(data, msgID, client) elif (msgID == MSG_PING_RES): self._console.printNotice('Notice: MSG_PING_RES') self.__handlePingRes(data, msgID, client) elif (msgID == MSG_DISCONNECT_REQ): self._console.printNotice('Notice: MSG_DISCONNECT_REQ') self.__handleDisconnect(data, msgID, client) # Pre-game server messages elif (msgID == MSG_AUTH_REQ): self._console.printNotice('Notice: MSG_AUTH_REQ') self.__handleAuth(data, msgID, client) elif (msgID == MSG_MAPLIST_REQ): self._console.printNotice('Notice: MSG_MAPLIST_REQ') #self.__handleMapList(data, msgID, client) elif (msgID == MSG_GAMELIST_REQ): self._console.printNotice('Notice: MSG_GAMELIST_REQ') self.__handleGameList(data, msgID, client) elif (msgID == MSG_NEWGAME_REQ): self._console.printNotice('Notice: MSG_NEWGAME_REQ') self.__handleNewGame(data, msgID, client) elif (msgID == MSG_JOINGAME_REQ): self._console.printNotice('Notice: MSG_JOINGAME_REQ') self.__handleJoinGame(data, msgID, client) elif (msgID == MSG_DOWNLOADMAP_REQ): self._console.printNotice('Notice: MSG_DOWNLOADMAP_REQ') self.__handleDownloadMap(data, msgID, client) elif (msgID == MSG_DOWNLOADUPD_REQ): self._console.printNotice('Notice: MSG_DOWNLOADUPD_REQ') self.__handleDownloadUpdate(data, msgID, client) # In-game server messages elif (msgID >= MSG_INGAME): self.__route(data, msgID, client) else: self._console.printNotice('%s: Unkown MSG_ID: %d'%(client.getAddress().getIpString(),msgID)) print(data) def __handlePingReq(self, data, msgID, client): ''' Respond to a ping request. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' # Send response pkg = NetDatagram() pkg.addUint16(MSG_PING_RES) self._cWriter.send(pkg, client) self._console.printNotice('%s: Ping request'%(client.getAddress().getIpString())) def __handlePingRes(self, data, msgID, client): ''' Handle an incoming ping response. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' self._console.printNotice('%s: Ping response'%(client.getAddress().getIpString())) # Client responded so remove from non-responder list try: del(self.pingNonResponders[client]) except KeyError: self._console.printNotice("%s responded to ping but was not in pingNonResponders"%client.getAddress()) def __handleDisconnect(self, data, msgID, client): ''' Disconnect and send confirmation to the client. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that tendNehis datagram came from''' # Create a response pkg = NetDatagram() pkg.addUint16(MSG_DISCONNECT_RES) self._cWriter.send(pkg, client) # If user has joined a game, remove the player from that game for g in self.games: if g.isPlayerInGame(client): g.removePlayer(client) # If user is logged in disconnect username = '' for u in self.connectedUsers: if (u.connectedClient == client): username = u.username u.disconnect() self.connectedUsers.remove(u) # Delete client from list if client in self.connections: self.connections.remove(client) # Don't worry about pings any more if client in self.pingNonResponders: del(self.pingNonResponders[client]) self._console.printNotice('%s: Disconnected user %s'%(client.getAddress().getIpString(),username)) def __handleAuth(self, data, msgID, client): ''' Try to authorize the connecting user, send the result. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' # Unpack message data username = data.getString() password = data.getString() auth = 0 # Look for the username in the list of registered users for u in self.registeredUsers: if u.username == username: if u.connected: auth = 1 self._console.printNotice('%s: User %s already connected'%(client.getAddress().getIpString(),username)) break elif u.password != password: auth = 2 self._console.printNotice('%s: User %s gave invalid password'%(client.getAddress().getIpString(),username)) break else: auth = 3 u.connect(client) self.connectedUsers.append(u) self._console.printNotice('%s: User %s connected with pass %s' %(client.getAddress().getIpString(),username,password)) # Send response pkg = NetDatagram() pkg.addUint16(MSG_AUTH_RES) pkg.addUint32(auth) self._cWriter.send(pkg, client) def __handleMapList(self, data, msgID, client): ''' Assemble a list of available maps and send it to the requesting client. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' # Assemble a list with entries in the form (filename,mapname,md5sum) mapFileList = Map.getMapFiles() responseList = [] for f in mapFileList: fh = open(Map.MAP_PATH + f,' rb') mapObj = cPickle.load(fh) responseList.append((mapObj.name, f, Map.getMapMD5(f))) # Send response pkg = NetDatagram() pkg.addUint16(MSG_MAPLIST_RES) pkg.addString('SOT') # Start Of Transmission for i, (n,f,c) in enumerate(responseList): pkg.addString(n) pkg.addString(f) pkg.addString(c) if i < len(responseList)-1: pkg.addString('T') # Still tranmitting pkg.addString('EOT') # End Of Transmission self._cWriter.send(pkg, client) self._console.printNotice('%s: Request for map list.' %(client.getAddress().getIpString())) def __handleGameList(self, data, msgID, client): ''' Assemble a list of active games and send it to the requesting client. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' # Send response pkg = NetDatagram() pkg.addUint16(MSG_GAMELIST_RES) if (len(self.games) == 0): pkg.addString('EOT') # Nothing to transmit else: pkg.addString('SOT') # Start Of Transmission for i,g in enumerate(self.games): pkg.addInt32(g.id) pkg.addString(g.name) pkg.addUint32(g.numPlayers) pkg.addString(g.map.name) pkg.addString(g.mapFile) pkg.addUint32(g.startTime) pkg.addUint32(g.turnNumber) if i < len(self.games)-1: pkg.addString('T') # Still tranmitting pkg.addString('EOT') # End Of Transmission self._cWriter.send(pkg, client) self._console.printNotice('%s: Request for game list.' %(client.getAddress().getIpString())) def __handleNewGame(self, data, msgID, client): ''' Create a new game and respond with success or failure. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that tendNehis datagram came from''' # Unpack message data gameName = data.getString() mapID = data.getString() numPlayers = data.getUint32() # If we do not have the map for the requested game tell client print("id=%s"%mapID) if(not self._mapStore.isAvailable(id=mapID)): response = 0 else: # Create the game newGame = GameStateServer(gameName, numPlayers, mapID) if newGame is not None: self.games.append(newGame) response = newGame.id else: response = -1 # Send response pkg = NetDatagram() pkg.addUint16(MSG_NEWGAME_RES) pkg.addInt32(response) self._cWriter.send(pkg, client) self._console.printNotice('%s: Request for new game: %s, %s, %d.' %(client.getAddress().getIpString(),gameName,mapID,numPlayers)) def __handleJoinGame(self, data, msgID, client): ''' Add client to the requested game. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that tendNehis datagram came from''' # Unpack message data id = data.getUint32() resp = 0 # Find the game game = None mapMD5 = "00000000000000000000000000000000" print self.games for g in self.games: if g.id == id: game = g mapMD5 = g.mapID if game == None: LOG.debug('No such game') resp = 0 elif len(game.connections) >= game.numPlayers: LOG.debug('Game full') resp = 1 else: game.addPlayer(client) LOG.debug('Ok, joining game') resp = 2 # Send response pkg = NetDatagram() pkg.addUint16(MSG_JOINGAME_RES) pkg.addUint32(resp) pkg.addString(mapMD5) self._cWriter.send(pkg, client) self._console.printNotice('%s: Request to join game id %d, gave %d.'%(client.getAddress().getIpString(),id,resp)) def __handleDownloadMap(data, msgID, client): ''' Prepare and send requested map to client data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that tendNehis datagram came from''' # Unpack message data id = data.getUint32() resp = 0 filename = self._mapStore.getMap(id=id)['filename'] mapString = self._mapStore.loadMapAsString(filename) if (mapString == None): LOG.debug('No such map') resp = 0 mapString = '' else: LOG.debug('Sending map') resp = 1 # Send response pkg = NetDatagram() pkg.addUint16(MSG_JOINGAME_RES) pkg.addUint32(resp) pkg.addString(mapString) self._cWriter.send(pkg, client) def __handleDownloadUpdate(data, msgID, client): pass def __route(self, data, msgID, client): LOG.notice('Routing msg to GameStateServer') def shutdown(self): print('Shutting down server ...') # Send disconnect to all clients pkg = NetDatagram() pkg.addUint16(MSG_DISCONNECT_REQ) for c in self.connections: self._cWriter.send(pkg, c) self._cManager.closeConnection(self._tcpSocket) print('Server done') sys.exit() def disconnect(self, client): ''' Disconnect client''' self.__handleDisconnect(None, None, client)
class LoginServer(ShowBase): def __init__(self, port, backlog=1000, compress=False): ShowBase.__init__(self) self.compress = compress self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.clientdb = ClientDataBase() if not self.clientdb.connected: self.clientdb = None print 'Login Server failed to start...' else: # This is for pre-login self.tempConnections = [] # This is for authed clients self.activeClients = [] # This is for authed servers self.activeServers = [] # This is for authed chat servers self.activeChats = [] self.connect(port, backlog) self.startPolling() self.taskMgr.doMethodLater(0.5, self.lobbyLoop, 'Lobby Loop') print 'Login Server operating...' def connect(self, port, backlog=1000): # Bind to our socket tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(tcpSocket) def startPolling(self): self.taskMgr.add(self.tskListenerPolling, "serverListenTask", -40) self.taskMgr.add(self.tskDisconnectPolling, "serverDisconnectTask", -39) def tskListenerPolling(self, task): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.tempConnections.append(newConnection) self.cReader.addConnection(newConnection) return Task.cont def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable() == True: connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection self.cReader.removeConnection(connection) # Check for if it was a client for client in self.activeClients: if client.connection == connection: print 'removing client' self.activeClients.remove(client) break # then check servers for server in self.activeServers: if server.connection == connection: self.activeServers.remove(server) break # then check servers for chat in self.activeChats: if chat.connection == connection: self.activeChats.remove(chat) break return Task.cont def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def encode(self, data, compress=False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data, con): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, con) # This will check and do the logins. def auth(self, datagram): # If in login state. con = datagram.getConnection() package = self.processData(datagram) if len(package) == 2: if package[0] == 'create': success, result = self.clientdb.addClient( package[1][0], package[1][1]) if success: self.sendData(('createSuccess', result), con) else: self.sendData(('createFailed', result), con) return False if package[0] == 'client': userFound = False for client in self.activeClients: if client.name == package[1][0]: userFound = True self.sendData(('loginFailed', 'logged'), con) break if not userFound: valid, result = self.clientdb.validateClient( package[1][0], package[1][1]) if valid: self.activeClients.append(Client(package[1][0], con)) self.sendData(('loginValid', result), con) return True else: self.sendData(('loginFailed', result), con) return False # if server add it to the list of current active servers if package[0] == 'server': self.activeServers.append(Server(package[1], con)) return True # if server add it to the list of current active servers if package[0] == 'chat': self.activeChats.append(Chat(package[1], con)) return True def getData(self): data = [] while self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): if datagram.getConnection() in self.tempConnections: if self.auth(datagram): self.tempConnections.remove(datagram.getConnection()) continue # Check if the data recieved is from a valid client. for client in self.activeClients: if datagram.getConnection() == client.connection: data.append( ('client', self.processData(datagram), client)) break # Check if the data recieved is from a valid server. for server in self.activeServers: if datagram.getConnection() == server.connection: data.append( ('server', self.processData(datagram), server)) break # Check if the data recieved is from a valid chat. for chat in self.activeChats: if datagram.getConnection() == chat.connection: data.append(('chat', self.processData(datagram), chat)) break return data # handles new joining clients and updates all clients of chats and readystatus of players def lobbyLoop(self, task): # if in lobby state temp = self.getData() if temp != []: for package in temp: # handle client incoming packages here if package[0] == 'client': # This is where packages will come after clients connect to the server # will be things like requesting available servers and chat servers if package[1] == 'server_query': for server in self.activeServers: if server.state == 'lobby': self.sendData( ('server', (server.name, str(server.connection.getAddress()))), package[2].connection) self.sendData(('final', 'No more servers'), package[2].connection) # handle server incoming packages here elif package[0] == 'server': # auth # game state change if len(package[1]) == 2: if package[1][0] == 'auth': clientAuth = False print 'Attempting Authentication on: ', package[1][ 1] for client in self.activeClients: if client.name == package[1][1]: clientAuth = True break if clientAuth: self.sendData(('auth', client.name), package[2].connection) else: self.sendData(('fail', package[1][1]), package[2].connection) elif package[1][0] == 'state': package[2].state = package[1][1] # handle chat server incoming packages here elif package[0] == 'chat': print 'Authorized chat server sent package' # handle packages from the chat servers # like making public/private # authing clients return task.again
class MiniServer: def __init__(self, host, port, channel, serverType): self.port = port self.host = host self.channel = channel self.serverType = serverType self.Connections = {} self.startConnectionMgr() self.locked = 0 #base.taskMgr.add(self.displayServerStatusTask, "displayServerStatus") return def connectToServer(self, port): # Connect our MiniServer to the main server. self.serverConnection = self.cMgr.openTCPClientConnection(self.host, port, 5000) if self.serverConnection: self.cReader.addConnection(self.serverConnection) self.handleConnected() def handleConnected(self): self.registerChannel() def registerChannel(self): dg = PyDatagram() dg.addServerControlHeader(CONTROL_ADD_CHANNEL) dg.addChannel(self.channel) self.cWriter.send(dg, self.serverConnection) print "Registered channel: " + str(self.channel) def setLocked(self, value): if value: self.locked = 1 elif not value: self.locked = 0 def displayServerStatusTask(self, task): self.displayServerStatus() task.delayTime = 30 return Task.again def displayServerStatus(self): print "-----------------------------------" print "Server Status..." print "Host: %s" % self.host print "Port: %s" % self.port print "Number of active connections: %s" % len(self.Connections) def startConnectionMgr(self): self.cMgr = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cMgr, 0) self.cReader = QueuedConnectionReader(self.cMgr, 0) self.cWriter = ConnectionWriter(self.cMgr, 0) self.tcpSocket = self.cMgr.openTCPServerRendezvous('', self.port, 10) self.cListener.addConnection(self.tcpSocket) taskMgr.add(self.listenerPoll, "listenForConnections", -39) taskMgr.add(self.datagramPoll, "listenForDatagrams", -40) taskMgr.add(self.disconnectionPoll, "listenForDisconnections", -41) print "%s server started." % self.serverType.capitalize() def listenerPoll(self, task): """ Listen for connections. """ if not self.locked: if self.cListener.newConnectionAvailable(): print "-----------------------------------" print "New connection available..." rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.Connections[str(newConnection.this)] = rendezvous self.cReader.addConnection(newConnection) print "IP Address: %s" % newConnection.getAddress() print "ConnectionID: %s" % newConnection.this self.displayServerStatus() #if self.__class__.__name__ == 'LoginServer': # self.sendServerMessage('ciac', # newConnection) return Task.cont def datagramPoll(self, task): if self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): self.handleDatagram(datagram) return Task.cont def disconnectionPoll(self, task): if self.cMgr.resetConnectionAvailable(): connectionPointer = PointerToConnection() self.cMgr.getResetConnection(connectionPointer) lostConnection = connectionPointer.p() print "-----------------------------------" print "Farewell connection..." print "IP Address: %s" % lostConnection.getAddress() print "ConnectionID: %s" % lostConnection.this del self.Connections[str(lostConnection.this)] self.cMgr.closeConnection(lostConnection) self.displayServerStatus() return Task.cont
class Server(ShowBase): def __init__(self): ShowBase.__init__(self) # Server Networking handling stuff self.compress = False self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.tempConnections = [] self.unauthenticatedUsers = [] self.users = [] self.passedData = [] self.connect(9099, 1000) self.startPolling() self.attemptAuthentication() self.taskMgr.doMethodLater(0.5, self.lobbyLoop, 'Lobby Loop') def connect(self, port, backlog = 1000): # Bind to our socket tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(tcpSocket) def startPolling(self): self.taskMgr.add(self.tskListenerPolling, "serverListenTask", -40) self.taskMgr.add(self.tskDisconnectPolling, "serverDisconnectTask", -39) def tskListenerPolling(self, task): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() newConnection.setNoDelay(True) self.tempConnections.append(newConnection) # Remember connection self.cReader.addConnection(newConnection) # Begin reading connection return Task.cont def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable() == True: connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) # remove from our activeConnections list if connection in self.tempConnections: self.tempConnections.remove(connection) for user in self.unauthenticatedUsers: if connection == user.connection: self.unauthenticatedUsers.remove(user) for user in self.users: if connection == user.connection: user.connection = None self.passData(('disconnect', user.name), None) return Task.cont def broadcastData(self, data): # Broadcast data out to all users for user in self.users: if user.connection: self.sendData(data, user.connection) def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def getUsers(self): # return a list of all users return self.users def encode(self, data, compress = False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data, con): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, con) def passData(self, data, connection): self.passedData.append((data, connection)) def getData(self): data = [] for passed in self.passedData: data.append(passed) self.passedData.remove(passed) while self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): if datagram.getConnection() in self.tempConnections: self.processTempConnection(datagram) continue for authed in self.users: if datagram.getConnection() == authed.connection: data.append((self.processData(datagram), datagram.getConnection())) return data def processTempConnection(self, datagram): connection = datagram.getConnection() package = self.processData(datagram) if len(package) == 2: if package[0] == 'username': print 'attempting to authenticate', package[1] self.tempConnections.remove(connection) if not self.online: user = User(package[1], connection) # confirm authorization self.sendData(('auth', user.name), user.connection) self.updateClient(user) self.users.append(user) else: self.client.sendData(('auth', package[1])) self.unauthenticatedUsers.append(User(package[1], connection)) def attemptAuthentication(self): config = ConfigParser.RawConfigParser() config.read('server.cfg') self.SERVER_NAME = config.get('SERVER DETAILS', 'serverName') config = ConfigParser.RawConfigParser() config.read('master.cfg') self.LOGIN_IP = config.get('MASTER SERVER CONNECTION', 'masterIp') self.LOGIN_PORT = config.getint('MASTER SERVER CONNECTION', 'masterPort') # Client for connecting to main server for showing exists and receiving clients self.client = Client(self, self.LOGIN_IP, self.LOGIN_PORT, compress = True) if self.client.getConnected(): self.client.sendData(('server', self.SERVER_NAME)) self.taskMgr.add(self.clientValidator, 'Client Validator') self.client.sendData(('state', 'lobby')) self.online = True else: # client not connected to login/auth server print 'Could not connect to Authentication Server.' print 'Server is not in online mode. No Authentication will happen for clients.' print 'Restart Server to attempt to connect to Authentication Server.' self.client = None self.online = False def clientValidator(self, task): temp = self.client.getData() for package in temp: if len(package) == 2: if package[0] == 'auth': print 'User authenticated: ', package[1] for user in self.unauthenticatedUsers: if user.name == package[1]: # confirm authorization self.sendData(('auth', user.name), user.connection) # send all required data to user self.updateClient(user) # all authenticated users self.users.append(user) self.unauthenticatedUsers.remove(user) print 'confirmation sent to ', package[1] break elif package[0] == 'fail': print 'User failed authentication: ', package[1] for user in self.unauthenticatedUsers: if user.name == package[1]: self.sendData(('fail', user.name), user.connection) self.unauthenticatedUsers.remove(user) break return task.again def updateClient(self, user): for existing in self.users: if existing.name != user.name: self.sendData(('client', existing.name), user.connection) self.sendData(('ready', (existing.name, existing.ready)), user.connection) if existing.connection: self.sendData(('client', user.name), existing.connection) self.sendData(('client', user.name), user.connection) def lobbyLoop(self, task): temp = self.getData() for package in temp: if len(package) == 2: print "Received: ", str(package) packet = package[0] connection = package[1] if len(packet) == 2: # check to make sure connection has username for user in self.users: if user.connection == connection: # if chat packet if packet[0] == 'chat': print 'Chat: ', packet[1] # Broadcast data to all clients ("username: message") self.broadcastData(('chat', (user.name, packet[1]))) # else if ready packet elif packet[0] == 'ready': print user.name, ' changed readyness!' user.ready = packet[1] self.broadcastData(('ready', (user.name, user.ready))) # else if disconnect packet elif packet[0] == 'disconnect': print user.name, ' is disconnecting!' self.users.remove(user) self.broadcastData(('disconnect', user.name)) # break out of for loop break # if all players are ready and there is X of them gameReady = True # if there is any clients connected if self.getUsers() == []: gameReady = False for user in self.users: if not user.ready: gameReady = False if gameReady: self.prepareGame() return task.done return task.again def prepareGame(self): if self.camera: # Disable Mouse Control for camera self.disableMouse() self.camera.setPos(0, 0, 500) self.camera.lookAt(0, 0, 0) self.gameData = GameData(True) # game data self.broadcastData(('gamedata', self.gameData.packageData())) self.broadcastData(('state', 'preround')) if self.online: self.client.sendData(('state', 'preround')) print "Preparing Game" self.gameTime = 0 self.tick = 0 usersData = [] for user in self.users: usersData.append(user.gameData) self.game = Game(self, usersData, self.gameData) self.taskMgr.doMethodLater(0.5, self.roundReadyLoop, 'Game Loop') print "Round ready State" def roundReadyLoop(self, task): temp = self.getData() for package in temp: if len(package) == 2: print "Received: ", str(package) if len(package[0]) == 2: for user in self.users: if user.connection == package[1]: if package[0][0] == 'round': if package[0][1] == 'sync': user.sync = True # if all players are ready and there is X of them roundReady = True # if there is any clients connected for user in self.users: if user.sync == False: roundReady = False if roundReady: self.taskMgr.doMethodLater(2.5, self.gameLoop, 'Game Loop') print "Game State" return task.done return task.again def gameLoop(self, task): # process incoming packages temp = self.getData() for package in temp: if len(package) == 2: # check to make sure connection has username for user in self.users: if user.connection == package[1]: user.gameData.processUpdatePacket(package[0]) # get frame delta time dt = self.taskMgr.globalClock.getDt() self.gameTime += dt # if time is less than 3 secs (countdown for determining pings of clients?) # tick out for clients while self.gameTime > gameTick: # update all clients with new info before saying tick for user in self.users: updates = user.gameData.makeUpdatePackets() for packet in updates: self.broadcastData((user.name, packet)) self.broadcastData(('tick', self.tick)) self.gameTime -= gameTick self.tick += 1 # run simulation if not self.game.runTick(gameTick): print 'Game Over' # send to all players that game is over (they know already but whatever) # and send final game data/scores/etc for user in self.users: user.ready = False self.taskMgr.doMethodLater(0.5, self.lobbyLoop, 'Lobby Loop') return task.done return task.cont
class Client(DirectObject): #----------------- # Initialization #----------------- def __init__(self): self.log = Log() self.log.Open('client.txt') self.clientSnapshotHandler = ClientSnapshotHandler() self.accept(EngineLoadedEvent.EventName, self.OnEngineLoadedEvent) self.fsm = ClientFSM(self) self.fsm.request('CreateNetworkObjects') self.lastServerPacketTimestamp = 0 def CreateNetworkObjects(self): if(self.CreateUDPConnection() and self.CreateTCPConnection()): self.dataHandler = ClientDataHandler(self) self.reliablePacketController = ReliablePacketController(self.cWriter, self.conn, self.dataHandler) self.unreliablePacketController = UnreliablePacketController(self.cWriter, self.conn, self.dataHandler) self.tcpPacketController = TCPPacketController(self.tcpWriter, self.tcpReader, self.cManager, self.dataHandler) self.dataHandler.SetPacketControllers(self.reliablePacketController, self.unreliablePacketController, self.tcpPacketController) self.ListenForIncomingTraffic() return True return False def CreateUDPConnection(self): self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.conn = self.cManager.openUDPConnection(Globals.PORT_CLIENT_LISTENER) if(self.conn): self.log.WriteLine('Connection on %s okay.' % (Globals.PORT_CLIENT_LISTENER)) else: self.log.WriteError('Connection on %s failed.' % (Globals.PORT_CLIENT_LISTENER)) Globals.PORT_CLIENT_LISTENER += 1 self.log.WriteError('Retrying on %s .' % (Globals.PORT_CLIENT_LISTENER)) self.conn = self.cManager.openUDPConnection(Globals.PORT_CLIENT_LISTENER) if(self.conn): self.log.WriteLine('Connection on %s okay.' % (Globals.PORT_CLIENT_LISTENER)) else: self.log.WriteError('Connection on %s failed.' % (Globals.PORT_CLIENT_LISTENER)) self.log.WriteError('Connection unsuccessful, exiting Client') return False self.cReader.addConnection(self.conn) return True def CreateTCPConnection(self): self.tcpWriter = ConnectionWriter(self.cManager,0) self.tcpReader = QueuedConnectionReader(self.cManager, 0) return True #--------------------- # Listening for data #--------------------- def ListenForIncomingTraffic(self): taskMgr.add(self.UDPPacketListenTask, "UDPPacketListenTask") taskMgr.add(self.TCPPacketListenTask, "TCPPacketListenTask", -40) def UDPPacketListenTask(self, task): while self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): #print 'PACKET', datagram data = PyDatagramIterator(datagram) ip = datagram.getAddress().getIpString() port = datagram.getAddress().getPort() peerAddr = NetAddress() peerAddr.setHost(ip, port) packetType = data.getUint8() if(packetType == Packet.PC_RELIABLE_PACKET): self.reliablePacketController.OnPacketReceived(data, peerAddr) elif(packetType == Packet.PC_UNRELIABLE_PACKET): self.unreliablePacketController.OnPacketReceived(data, peerAddr) elif(packetType == Packet.PC_ENVIRONMENT_PACKET): self.dataHandler.OnDataReceived(data, peerAddr, Packet.PC_ENVIRONMENT_PACKET) return Task.cont def TCPPacketListenTask(self, task): if self.tcpReader.dataAvailable(): datagram = NetDatagram() if self.tcpReader.getData(datagram): data = PyDatagramIterator(datagram) ip = datagram.getAddress().getIpString() port = datagram.getAddress().getPort() peerAddr = NetAddress() peerAddr.setHost(ip, port) packetType = data.getUint8() if(packetType == Packet.PC_TCP_PACKET): self.tcpPacketController.OnPacketReceived(data, peerAddr) return task.cont #--------------- # Sending Data #--------------- def ConnectToServer(self, serverAddress): self.fsm.request('WaitingForJoinResponse') self.log.WriteLine('Requesting to join server (%s)' % serverAddress) serverAddr = NetAddress() serverAddr.setHost(serverAddress, Globals.PORT_SERVER_LISTENER) self.dataHandler.SetServerAddress(serverAddr) self.dataHandler.SendRequestToJoinServer() self.acceptOnce(ServerJoinResponseEvent.EventName, self.OnServerJoinResponseEvent) taskMgr.doMethodLater(1.8, self.OnRequestJoinTimeout, 'serverJoinTimeout', extraArgs = [False]) # def SendChatMessage(self, messageType, message): # self.dataHandler.SendChatMessage(messageType, message) # def OnServerChatMessage(self, messageType, pid, message): # self.engine.OnServerChatMessage(messageType, pid, message) def SendInput(self, currentTime, myInput, myState): self.dataHandler.SendInputCommands(currentTime, myInput, myState) #self.game.ClearMyClicking() # def SendSelectedTeam(self, team): # self.dataHandler.SendSelectedTeam(team) def StoreSnapshot(self, t, myInput, myState): #myInput.SetTimestamp(t) snapshot = Snapshot(myInput, myState.GetValue(PlayerState.POSITION), t) self.clientSnapshotHandler.AddSnapshot(snapshot) def HandleEnvironmentChange(self, destroyed, added): self.engine.HandleEnvironmentChange(destroyed, added) def HandleServerPlayerStates(self, playerStates): if(self.engine is not None): self.engine.GetPlayerController().HandleServerPlayerStates(playerStates) # def UpdatePlayerState(self, playerId, key, value): # self.engine.UpdatePlayerState(playerId, key, value) # def OnPlayerDisconnect(self, pid): # self.engine.RemovePlayer(pid) # def OnConnectedPlayers(self, players): # for player in players: # self.engine.AddNewPlayer(player[0], player[1]) def CompareSnapshots(self, playerStates): if(self.engine is not None): if(Globals.MY_PID in playerStates.keys()): myState = playerStates[Globals.MY_PID] oldStates = self.clientSnapshotHandler.GetOldStates(myState.GetValue(PlayerState.TIMESTAMP)) self.engine.GetPlayerController().VerifyPrediction(copy.deepcopy(myState), oldStates) def OnRequestJoinTimeout(self, task): taskMgr.remove('serverJoinTimeout') self.reliablePacketController.RemovePeerData(self.dataHandler.serverAddr) self.unreliablePacketController.RemovePeerData(self.dataHandler.serverAddr) ServerJoinResponseEvent(False, 'Server could not be reached.').Fire() def OnServerJoinResponseEvent(self, event): #self.fsm.request('WaitingForEnvironment') print 'removed timeout message' taskMgr.remove('serverJoinTimeout') def LoadEngine(self): LoadEngineEvent().Fire() def OnEngineLoadedEvent(self, event): self.dataHandler.SendEngineLoaded() def GetPlayer(self, pid): return self.engine.GetPlayerController().GetPlayer(pid) def Disconnect(self): self.fsm.request('Idle', 'Left Server') def CleanUp(self): self.reliablePacketController.CleanUp() self.unreliablePacketController.CleanUp() def Exit(self): self.log.Close()
class ClientConnection(object): ''' This class creates the communication links to a game server and presents an interface for communication.''' __metaclass__ = Singleton address = 'chadrempp.com' port = '9091' timeout = '3000' _callback = None _connected = False _authorized = False _connectedGame = None _respCallback = {MSG_AUTH_RES: None, MSG_MAPLIST_RES: None, MSG_GAMELIST_RES: None, MSG_NEWGAME_RES: None, MSG_JOINGAME_RES: None} def __init__(self): ''' ClientConnection constructor.''' self._cManager = QueuedConnectionManager() self._cListener = QueuedConnectionListener(self._cManager, 0) self._cReader = QueuedConnectionReader(self._cManager, 0) self._cWriter = ConnectionWriter(self._cManager,0) def isConnected(self): ''' Return True if a connection is established, otherwise False.''' return self._connected def isAuthorized(self): ''' Return True if the connection is authorized, otherwise False.''' return self._authorized def authenticate(self, username, password, callback): ''' Send authentication request. username (string): Username for authentication password (string): Password for authentication callback (function): Funtion that will be called when a response is received. Callback will be passed one parameter (status) status = 0 if authorization failed status = 1 if the user is already authenticated status = 2 if an invalid password is supplied status = 3 if authentication succeeded ''' self.__sendAuthReq(username, password) self._respCallback[MSG_AUTH_RES] = callback def connect(self, address, port, timeout, callback=None): ''' Try to connect to the server. address (String): address for the server port (Int): port to connect to timeout (Int): how long to wait before giving up (milliseconds) callback (function): Funtion that will be called when a response is received. Callback will be passed one parameter (status) status = True if connection succeeded status = False if connection failed ''' if self._connected: LOG.notice("Already Connected!") else: self._connected = False try: LOG.notice('connecting to %s'%address) self._tcpSocket = self._cManager.openTCPClientConnection(address, port, timeout) if self._tcpSocket: LOG.notice("Opened socket.") self._cReader.addConnection(self._tcpSocket) # receive messages from server if self._cReader: taskMgr.add(self.__readTask,"Poll the connection reader",-40) taskMgr.doMethodLater(PING_DELAY, self.__pingTask, 'serverPingTask', sort=-41) self._connected = True LOG.notice("Created listener") else: LOG.error("Couldn't connect to server") else: LOG.error("Couldn't connect to server") except Exception: LOG.error("Couldn't connect to server") if callback: callback(self._connected) def disconnect(self, callback): ''' Disconnect from the server. callback (function): Funtion that will be called when a response is received. Callback will be passed one parameter (status) status = 1 if connection succeeded status = 0 if connection failed ''' if self._connected: LOG.notice('Disconnecting...') pkg = NetDatagram() pkg.addUint16(MSG_DISCONNECT_REQ) self._cWriter.send(pkg, self._tcpSocket) self._cManager.closeConnection(self._tcpSocket) self._connected = False if callback != None: callback(1) else: LOG.error('Can not disconnect, we are not connected.') if callback != None: callback(0) def getMapList(self, callback): ''' Send a request for a list of maps available on the server. callback (function): Funtion that will be called when a response is received. Callback will be passed one parameter (mapDictList). mapDictList is a list of dictionaries, each dictionary represents a map. The following keys will be available in each dictionary. 'filename' - The map filename 'mapname' - The name of the map 'md5sum' - The unique MD5 ID of the map ''' self.__sendMapListReq() self._respCallback[MSG_MAPLIST_RES] = callback def getGameList(self, callback): ''' Sends a request for a list of active games to the server. callback (function): Funtion that will be called when a response is received. Callback will be passed one parameter (gameDictList). gameDictList is a list of dictionaries, each dictionary represents a game. The following keys will be available in each dictionary. 'id' - The game ID 'name' - The game's name 'numplayer' - The number of players for this game 'mapname' - The name of the map for this game 'mapfilename' - The filename of the map for this game 'starttime' - The game's start time 'turnnumber - The game's turn number ''' self.__sendGameListReq() self._respCallback[MSG_GAMELIST_RES] = callback def newGame(self, gamename, mapID, numplayers, callback): ''' Send info to start a new game on the server. gamename (string): The name of the game mapID (string): The unique MD5 ID of the map to use for this game numplayers (int): The number of players allowed for this game callback (function): Funtion that will be called when a response is received. Callback will be passed one parameter (status). status = -1 if the server failed to create the game status = 0 if the server needs the map in order to create status = x if the server succeeded in creating the game (x is the game ID) ''' self.__sendNewGameReq(gamename, mapID, numplayers) self._respCallback[MSG_NEWGAME_RES] = callback def joinGame(self, gameid, callback): ''' Attempt to join the game with ID=gameid. gameid (int): The ID of the game to join callback (function): Funtion that will be called when a response is received. Callback will be passed two parameters (status and mapMD5). status = 0 if no such game exists status = 1 if game is full status = 2 if joining game was successful ''' self.__sendJoinGameReq(gameid) self._respCallback[MSG_JOINGAME_RES] = callback def downloadMap(self, mapid, callback): ''' Download the map with the given id (MD5). mapid (string): The MD5 id of the map to download. callback (function): Funtion that will be called when a response is received. Callback will be passed two parameters (status and mapMD5). status = 0 if no such map exists status = 1 if download was successful ''' self._respCallback[MSG_DOWNLOADMAP_RES] = callback self._download("MAP", mapid) def registerGame(self, game, callback): ''' Tell server we are loaded and ready. The game ID is returned. game (Game): The game to be registered. callback (function): Funtion that will be called when a response is received. Callback will be passed one parameter (status). status = 0 if registration fails status > 0 the id of the game on success ''' id = 1 callback(id) def sendUnitMove(self, movedentity, callback): ''' Send updated entity to server.''' self.__sendUnitMove(movedentity) self._respCallback[MSG_UNITMOVE_RES] = callback def sendUnitAttack(self, fromentity, toentity, callback): ''' Send a message that fromentity attacked toentity. The entities have been updated from the attack.''' self.__sendUnitAttack(fromentity, toentity) self._respCallback[MSG_UNITATTACK_RES] = callback def sendUnitInfo(self, entity): ''' Send a requst for information about the given entity.''' self.__sendUnitInfo(entity) self._respCallback[MSG_UNITINFO_RES] = callback #--ClientConnection Private Methods---------------------------------------- def __readTask(self, taskdata): ''' This task listens for any messages coming in over any connections. If we get a connection passes it to the datagram handler.''' if self._cReader.dataAvailable(): datagram=NetDatagram() # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self._cReader.getData(datagram): data = PyDatagramIterator(datagram) msgID = data.getUint16() else: data = None msgID = MSG_NONE else: datagram = None data = None msgID = MSG_NONE if msgID is not MSG_NONE: self.__handleDatagram(data, msgID, datagram.getConnection()) return Task.cont def __pingTask(self, Task): ''' Ping the server every PING_DELAY seconds to check if it's still there.''' LOG.debug('Pinging') # Add task back into the taskmanager taskMgr.doMethodLater(PING_DELAY, self.__pingTask, 'serverPingTask', sort=-41) def __downloadTask(self, Task): if self.channel.run(): # Still waiting for file to finish downloading. return task.cont if not self.channel.isDownloadComplete(): print "Error downloading file." return task.done data = self.rf.getData() print "got data:" print data return task.done def __handleDatagram(self, data, msgID, client): ''' This handles incoming messages by calling the appropriate handler. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' if (msgID == MSG_PING_REQ): self.__recievePingReq(data, msgID, client) elif (msgID == MSG_DISCONNECT_REQ): self.__recieveDisconnectReq(data, msgID, client) elif (msgID == MSG_AUTH_RES): self.__recieveAuthRes(data, msgID, client) elif (msgID == MSG_MAPLIST_RES): self.__recieveMapListRes(data, msgID, client) elif (msgID == MSG_GAMELIST_RES): self.__recieveGameListRes(data, msgID, client) elif (msgID == MSG_NEWGAME_RES): self.__recieveNewGameRes(data, msgID, client) elif (msgID == MSG_JOINGAME_RES): self.__recieveJoinGameRes(data, msgID, client) elif (msgID == MSG_CHAT_RECV): self.__recieveChatRes(data, msgID, client) elif (msgID == MSG_UNITMOVE_RECV): self.__recieveUnitMove(data, msgID, client) elif (msgID == MSG_UNITATTACK_RECV): self.__recieveUnitAttack(data, msgID, client) elif (msgID == MSG_UNITINFO_RECV): self.__recieveUnitInfo(data, msgID, client) elif (msgID == MSG_ENDTURN_RECV): self.__recieveEndTurn(data, msgID, client) else: LOG.error("Unkown MSG_ID: %d " %msgID), print(data) def __recievePingReq(self, data, msgID, client): ''' Handle pings from the server. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' LOG.debug("Recieved a ping request") # Send response pkg = NetDatagram() pkg.addUint16(MSG_PING_RES) self._cWriter.send(pkg, self._tcpSocket) def __recieveDisconnectReq(self, data, msgID, client): ''' Handle a disconnect request from the server. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' LOG.notice("Server told us it was leaving! Disconecting") self._cManager.closeConnection(self._tcpSocket) self._connected = False def __sendAuthReq(self, username, password): ''' Send user name and password. The password is encypted first using SHA256. username (String): the username password (String): the password''' if self._connected: LOG.notice("Sending authorization") h = hashlib.sha256() h.update(password) pkg = NetDatagram() pkg.addUint16(MSG_AUTH_REQ) pkg.addString(username) pkg.addString(h.hexdigest()) self._cWriter.send(pkg, self._tcpSocket) else: LOG.error("Cant authorize, we are not connected") def __recieveAuthRes(self, data, msgID, client): ''' Recieve the authentication response from the server and deal with it by continuing or diconnecting. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' # Unpack message data response = data.getUint32() if (response == 0): LOG.error("Authorization for server failed for an unknown reason.") self.disconnect(None) elif (response == 1): LOG.error("You are already connected to this server. This could be due to an unclean disconnect.") elif (response == 2): LOG.error("Incorrect password") elif (response == 3): LOG.notice("Authorization granted.") self._authorized = True # If there is a callback function pass the game list to it if self._respCallback[MSG_AUTH_RES]: self._respCallback[MSG_AUTH_RES](response) self._respCallback[MSG_AUTH_RES] = None def __sendGameListReq(self): ''' Request a list of games on the connected server.''' # Send request if (self._connected and self._authorized): pkg = NetDatagram() pkg.addUint16(MSG_GAMELIST_REQ) self._cWriter.send(pkg, self._tcpSocket) def __recieveGameListRes(self, data, msgID, client): ''' Recieve the list of games requested. data (PyDatagramIterator): the list of data sent with this datagram msgID (Int): the message ID client (Connection): the connection that this datagram came from''' games = [] # Unpack message data indicator = data.getString() while (indicator != 'EOT'): id = data.getInt32() name = data.getString() maxPlayers = data.getUint32() mapName = data.getString() mapFileName = data.getString() startTime = data.getUint32() turnNumber = data.getUint32() indicator = data.getString() games.append({'id':id, 'name':name, 'numplayers':maxPlayers, 'mapname':mapName, 'mapfilename':mapFileName, 'starttime':startTime, 'turnnumber':turnNumber}) # If there is a callback function pass the game list to it if self._respCallback[MSG_GAMELIST_RES]: self._respCallback[MSG_GAMELIST_RES](games) #self._availableGames = games def __sendNewGameReq(self, gamename, mapID, numplayers): ''' Create a new game on the server. name (String): the name of the game mapID (String): the MD5 ID of the map maxplayers (Int): the max players allowed''' LOG.debug('Sending new game request %s'%map) # Send Request if (self._connected and self._authorized): pkg = NetDatagram() pkg.addUint16(MSG_NEWGAME_REQ) pkg.addString(gamename) pkg.addString(mapID) pkg.addUint32(numplayers) self._cWriter.send(pkg, self._tcpSocket) def __recieveNewGameRes(self, data, msgID, client): ''' Recieve the response of our attempt to create a new game.''' LOG.debug('Recieving new game response') # Unpack message data game_created = data.getInt32() # If there is a callback function pass the response to it if self._respCallback[MSG_NEWGAME_RES]: self._respCallback[MSG_NEWGAME_RES](game_created) self._respCallback[MSG_NEWGAME_RES] = None def __sendJoinGameReq(self, id): ''' Join a game on the server. id (int): the id of the game to join''' LOG.debug('Sending join game request') # Send Request if (self._connected and self._authorized): pkg = NetDatagram() pkg.addUint16(MSG_JOINGAME_REQ) pkg.addUint32(id) self._cWriter.send(pkg, self._tcpSocket) def __recieveJoinGameRes(self, data, msgID, client): ''' Handle the response to a join game request.''' LOG.debug("Recieving joing game response") # Unpack message data join_response = data.getUint32() map_md5 = data.getString() # If there is a callback function pass the response to it if self._respCallback[msgID]: self._respCallback[msgID](join_response, map_md5) self._respCallback[msgID] = None def _sendDownloadReq(type, id): ''' Download a file from the server.''' LOG.debug("Downloading type=%s, id=%s"%(type, id)) if (self._connected and self._authorized): pkg = NetDatagram() if (type == "MAP"): pkg.addUint16(MSG_DOWNLOADMAP_REQ) pkg.addUint32(id) elif (type == "UPDATE"): pkg.addUint16(MSG_DOWNLOADUPD_REQ) pkg.addUint32(id) self._cWriter.send(pkg, self._tcpSocket) def __sendChat(self, message): ''' Send chat message to the server.''' LOG.debug('Sending chat') def __recieveChat(self, data, msgID, client): ''' Recieve chat message from server.''' LOG.debug('Recieved chat') def __sendUnitMove(self, entity): ''' Send the updated entity to the server.''' LOG.debug('Sending move') def __recieveUnitMove(self, data, msgID, client): ''' Recieve an updated entity.''' LOG.debug('Recieved move') def __sendUnitAttack(self, fromentity, toentity): ''' Send a an attacking entity (fromentity) and an attacked entity (toentity).''' LOG.debug('Sending attack') def __recieveUnitAttack(self, data, msgID, client): ''' Recieve an attack from the server.''' LOG.debug('Recieved attack') def __sendUnitInfo(self, entity): ''' Send a request for info on an entity.''' LOG.debug('Sending info request') def __recieveUnitInfo(self, data, msgID, client): ''' Recieve unit info.''' LOG.debug('Recieving unit info') def __sendEndTurn(self): ''' Send end turn request.''' LOG.debug('Sending end turn') def __recieveEndTurn(self, data, msgID, client): ''' Recieve end turn.''' LOG.debug('Recieving end turn.') def __del__(self): ''' This destructor tells the server we are leaving so things do not get too messy.''' self.disconnect()
class Server: def __init__(self, port, backlog=1000, compress=False): self.port = port self.backlog = backlog self.compress = compress self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.activeConnections = [] # We'll want to keep track of these later self.connect(self.port, self.backlog) self.startPolling() def connect(self, port, backlog=1000): # Bind to our socket self.tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(self.tcpSocket) def disconnect(self, port, backlog=1000): self.tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cManager.closeConnection(self.tcpSocket) taskMgr.remove("serverListenTask") taskMgr.remove("serverDisconnectTask") def startPolling(self): taskMgr.add(self.tskListenerPolling, "serverListenTask", -40) taskMgr.add(self.tskDisconnectPolling, "serverDisconnectTask", -39) def tskListenerPolling(self, task): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.activeConnections.append( newConnection) # Remember connection self.cReader.addConnection( newConnection) # Begin reading connection return Task.cont def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable() == True: connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) # Loop through the activeConnections till we find the connection we just deleted # and remove it from our activeConnections list for c in range(0, len(self.activeConnections)): if self.activeConnections[c] == connection: del self.activeConnections[c] break return Task.cont def broadcastData(self, data): # Broadcast data out to all activeConnections for con in self.activeConnections: self.sendData(data, con) def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def getClients(self): # return a list of all activeConnections return self.activeConnections def encode(self, data, compress=False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data, con): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, con) def getData(self): data = [] while self.cReader.dataAvailable(): datagram = NetDatagram( ) # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self.cReader.getData(datagram): data.append(self.processData(datagram)) return data
class Server(DirectObject): def __init__(self): self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.activeConnections = [] # Keeps tracks of active connections #Set up the connection port_address=9099 #No-other TCP/IP services are using this port backlog=1000 #If we ignore 1,000 connection attempts, something is wrong! self.tcpSocket = self.cManager.openTCPServerRendezvous(port_address,backlog) self.cListener.addConnection(self.tcpSocket) self.setTaskManagers() #Set the Managers def tskListenerPolling(self,taskdata): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous,netAddress,newConnection): newConnection = newConnection.p() self.activeConnections.append(newConnection) # Remember connection self.cReader.addConnection(newConnection) # Begin reading connection self.broadCast(newConnection) #Broadcasts the Server Message return Task.cont def tskReaderPolling(self,taskdata): if self.cReader.dataAvailable(): datagram = NetDatagram() # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self.cReader.getData(datagram): myProcessDataFunction(datagram) return Task.cont def setTaskManagers(self): taskMgr.add(self.tskListenerPolling,"Poll the connection listener",-39) taskMgr.add(self.tskReaderPolling,"Poll the connection reader",-40) ''' Terminate all connections. ''' def terminateAllConnection(self): for aClient in self.activeConnections: self.cReader.removeConnections(aClient) self.activeConnections = [] #Close our listener self.cManager.closeConnection(self.tcpSocket) ''' Terminate a connection. ''' def terminateConnection(self, aClient): self.cReader.removeConnections(aClient) ''' PyDatagram for messages Arguments: message must be a string ''' def messageData(self, message): messDat = PyDatagram() messDat.addUint8(PRINT_MESSAGE) messDat.addString(message) return messDat ''' Broadcast Server Message ''' def broadCast(self, aClient): message = self.messageData("Welcome to BaziBaz's Server\nConnection has been estabilished\n") self.cWriter.send(message, aClient)
class LoginServer: def __init__(self, port, backlog=1000, compress=False): self.port = port self.backlog = backlog self.compress = compress self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.db = DataBase() # This is for pre-login self.tempConnections = [] # This is for authed clients self.activeConnections = [] # Temp user dict self.clients = {} self.connect(self.port, self.backlog) self.startPolling() def connect(self, port, backlog=1000): # Bind to our socket tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(tcpSocket) def startPolling(self): taskMgr.add(self.tskListenerPolling, "serverListenTask", -40) taskMgr.add(self.tskDisconnectPolling, "serverDisconnectTask", -39) def tskListenerPolling(self, task): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.tempConnections.append(newConnection) # Lets add it to a temp list first. self.cReader.addConnection(newConnection) # Begin reading connection # Make the temp place holder then add to temp, under dataget check the temp list, if something ther do # auth and then add to the active return Task.cont def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable() == True: print "disconnect" connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) for u in range(len(self.clients)): if self.clients[u]["connection"] == connection: del self.clients[u] break # Loop through the activeConnections till we find the connection we just deleted # and remove it from our activeConnections list for c in range(0, len(self.activeConnections)): if self.activeConnections[c] == connection: del self.activeConnections[c] break return Task.cont def broadcastData(self, data): # Broadcast data out to all activeConnections for con in self.activeConnections: self.sendData(data, con) def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def getClients(self): # return a list of all activeConnections return self.activeConnections def encode(self, data, compress=False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data, con): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, con) # This will check and do the logins. def auth(self, datagram): # If in login state. clientIp = datagram.getAddress() # This is the ip :P clientCon = datagram.getConnection() # This is the connection data. used to send the shit. package = self.processData(datagram) print "SERVER: ", package valid_packet = False if len(package) == 2: # if login request is send reply # Should add a checker like in the db something like isLogged(0 or 1) # If found then say no for client user_found = False if package[0] == "login_request": valid_packet = True print "Try login" for u in range(len(self.clients)): if self.clients[u]["name"] == package[1][0]: print "User already exists" user_found = True data = {} data[0] = "error" data[1] = "User already logged in" self.sendData(data, clientCon) break # send something back to the client saying to change username if not user_found: username = package[1][0] password = package[1][1] self.db.Client_getLogin(username, password) if self.db.login_valid: # Add the user new_user = {} new_user["name"] = package[1][0] new_user["connection"] = clientCon new_user["ready"] = False new_user["new_dest"] = False new_user["new_spell"] = False self.clients[len(self.clients)] = new_user # Send back the valid check. data = {} data[0] = "login_valid" # If client gets this the client should switch to main_menu. data[1] = {} data[1][0] = self.db.status data[1][1] = len(self.clients) - 1 # This is part of the old 'which' packet self.sendData(data, clientCon) # Move client to the self.activeConnections list. self.activeConnections.append(clientCon) print "HERE IS ACTIVE: ", self.activeConnections self.tempConnections.remove(clientCon) print "HERE IS TEMP", self.tempConnections else: status = self.db.status data = {} data[0] = "db_reply" data[1] = status self.sendData(data, clientCon) if not valid_packet: data = {} data[0] = "error" data[1] = "Wrong Packet" self.sendData(data, clientCon) print "Login Packet not correct" else: print "Data in packet wrong size" def getData(self): data = [] while self.cReader.dataAvailable(): datagram = NetDatagram() # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self.cReader.getData(datagram): if datagram.getConnection() in self.tempConnections: print "Check Auth!" self.auth(datagram) print "Auth Done!" # in auth def or after the connection will be moved to self.activeConnections # and then removed from the temp list break # Check if the data rechieved is from a valid client. elif datagram.getConnection() in self.activeConnections: appendage = {} appendage[0] = self.processData(datagram) appendage[1] = datagram.getConnection() data.append(appendage) return data
class Server: def __init__(self, port, backlog=1000, compress=False): self.port = port self.backlog = backlog self.compress = compress self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.activeConnections = [] # We'll want to keep track of these later self.connect(self.port, self.backlog) self.startPolling() def connect(self, port, backlog=1000): # Bind to our socket tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(tcpSocket) def startPolling(self): taskMgr.add(self.tskListenerPolling, "serverListenTask", -40) taskMgr.add(self.tskDisconnectPolling, "serverDisconnectTask", -39) def tskListenerPolling(self, task): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.activeConnections.append(newConnection) # Remember connection self.cReader.addConnection(newConnection) # Begin reading connection return Task.cont def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable() == True: connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) # Loop through the activeConnections till we find the connection we just deleted # and remove it from our activeConnections list for c in range(0, len(self.activeConnections)): if self.activeConnections[c] == connection: del self.activeConnections[c] break return Task.cont def broadcastData(self, data): # Broadcast data out to all activeConnections for con in self.activeConnections: self.sendData(data, con) def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def getClients(self): # return a list of all activeConnections return self.activeConnections def encode(self, data, compress=False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data, con): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, con) def getData(self): data = [] while self.cReader.dataAvailable(): datagram = NetDatagram() # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self.cReader.getData(datagram): data.append(self.processData(datagram)) return data
class SocketServer(): def __init__(self, port, virtual_world, camera_mgr, sync_session): self.port = port self.virtual_world = virtual_world self.cam_mgr = camera_mgr self.task_mgr = virtual_world.taskMgr self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cReader.setRawMode(True) self.cWriter = ConnectionWriter(self.cManager, 1) self.cWriter.setRawMode(True) self.tcpSocket = self.cManager.openTCPServerRendezvous(port, BACKLOG) self.cListener.addConnection(self.tcpSocket) self.activeSessions = {} self.connection_map = {} self.set_handlers() hostname = socket.gethostname() a, b, address_list = socket.gethostbyname_ex(hostname) self.ip = address_list[0] logging.info("Addresses %s" % address_list) logging.info("Server is running on ip: %s, port: %s" % (self.ip, self.port)) self.client_counter = 0 self.read_buffer = '' self.read_state = 0 self.read_body_length = 0 self.packet = SocketPacket() controller = virtual_world.getController() self.sync = Sync(self.task_mgr, controller, camera_mgr, sync_session) self.vv_id = None if sync_session: logging.info("Waiting for Sync Client!") self.showing_info = False virtual_world.accept("i", self.toggleInfo) self.sync_session = sync_session self.createInfoLabel() atexit.register(self.exit) def createInfoLabel(self): string = self.generateInfoString() self.info_label = OST(string, pos=(-1.3, -0.5), fg=(1, 1, 1, 1), bg=(0, 0, 0, 0.7), scale=0.05, align=TextNode.ALeft) self.info_label.hide() def generateInfoString(self, ): string = " IP:\t%s \n" % self.ip string += " PORT:\t%s \n" % self.port if self.sync_session: string += " MODE:\tSync Client\n" string += " VV ID:\t%s\n" % self.vv_id else: string += " MODE:\tAutomatic\n" cameras = self.cam_mgr.getCameras() num_cameras = len(cameras) for camera in cameras: id = camera.getId() type = camera.getTypeString() string += " Cam%s:\t%s\n" % (id, type) string += "\n" return string def set_handlers(self): self.task_mgr.add(self.connection_polling, "Poll new connections", -39) self.task_mgr.add(self.reader_polling, "Poll reader", -40) self.task_mgr.add(self.disconnection_polling, "PollDisconnections", -41) def connection_polling(self, taskdata): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConn = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConn): conn = newConn.p() self.cReader.addConnection(conn) # Begin reading connection conn_id = self.client_counter logging.info("New Connection from ip:%s, conn:%s" % (conn.getAddress(), conn_id)) self.connection_map[conn_id] = conn self.client_counter += 1 message = eVV_ACK_OK(self.ip, self.port, conn_id) self.sendMessage(message, conn) return Task.cont def reader_polling(self, taskdata): if self.cReader.dataAvailable(): datagram = NetDatagram( ) # catch the incoming data in this instance # Check the return value; if we were threaded, someone else could have # snagged this data before we did if self.cReader.getData(datagram): self.read_buffer = self.read_buffer + datagram.getMessage() while (True): if self.read_state == 0: if len(self.read_buffer) >= self.packet.header_length: bytes_consumed = self.packet.header_length self.packet.header = self.read_buffer[:bytes_consumed] self.read_body_length = self.packet.decode_header() self.read_buffer = self.read_buffer[bytes_consumed:] self.read_state = 1 else: break if self.read_state == 1: if len(self.read_buffer) >= self.read_body_length: bytes_consumed = self.read_body_length self.packet.data = self.read_buffer[:bytes_consumed] self.packet.offset = 0 self.read_body_length = 0 self.read_buffer = self.read_buffer[bytes_consumed:] self.read_state = 0 self.new_data_callback(self.packet) else: break return Task.cont def new_data_callback(self, packet): packet = copy.deepcopy(packet) message_type = packet.get_int() conn_id = packet.get_int() if message_type == VP_SESSION: conn = self.connection_map[conn_id] type = packet.get_char() pipeline = packet.get_char() logging.debug("Received VP_SESSION message from conn:%s, " \ "type=%s, pipeline=%s" %(conn_id, VP_TYPE[type], PIPELINE[pipeline])) self.newVPSession(conn, type, pipeline, conn_id) elif message_type == SYNC_SESSION: vv_id = packet.get_int() self.vv_id = vv_id string = self.generateInfoString() self.info_label.setText(string) conn = self.connection_map[conn_id] logging.debug("Received SYNC_SESSION message from conn:%s" % conn_id) self.newSyncSession(conn, conn_id, vv_id) logging.info("Sync client connected") elif message_type == VP_REQ_CAM_LIST: logging.debug("Received VP_REQ_CAM_LIST message from conn:%s" % conn_id) cameras = self.cam_mgr.getCameras() pipeline = self.activeSessions[conn_id].getPipeline() camera_type = None if pipeline == STATIC_PIPELINE: camera_type = VP_STATIC_CAMERA elif pipeline == PTZ_PIPELINE: camera_type = VP_ACTIVE_CAMERA cam_list = [] for camera in cameras: if camera_type == camera.getType() and not camera.hasSession(): cam_list.append(camera.getId()) message = eVV_CAM_LIST(self.ip, self.port, cam_list) conn = self.connection_map[conn_id] logging.debug("Sent VV_CAM_LIST message to conn:%s" % conn_id) self.sendMessage(message, conn) elif message_type == VP_REQ_IMG: cam_id = packet.get_int() frequency = packet.get_char() width = packet.get_int() height = packet.get_int() jpeg = packet.get_bool() data = (frequency, width, height, jpeg) camera = self.cam_mgr.getCameraById(cam_id) logging.debug("Received VV_REQ_IMG message from conn:%s" % conn_id) if camera and not camera.hasSession(): session = self.activeSessions[conn_id] session.addCamera(cam_id) camera.setSession(session, VP_BASIC, self.ip, self.port, data) else: if conn_id in self.activeSessions: self.activeSessions[conn_id].newMessage(message_type, packet) def newVPSession(self, conn, type, pipeline, conn_id): if type == VP_ADVANCED: camera_type = -1 if pipeline == STATIC_PIPELINE: camera_type = STATIC_CAMERA ## Change this to use a different static camera class elif pipeline == PTZ_PIPELINE: camera_type = ACTIVE_CAMERA if camera_type != -1: cam = self.cam_mgr.getAvailableCamera(camera_type) if cam: session = VPSession(conn_id, conn, self, VP, pipeline) session.addCamera(cam.getId()) self.activeSessions[conn_id] = session message = eVV_VP_ACK_OK(self.ip, self.port, cam.getId()) logging.debug("Sent VV_VP_ACK_OK message to conn:%s" % conn_id) self.sendMessage(message, conn) cam.setSession(session, type, self.ip, self.port) else: message = eVV_VP_ACK_FAILED(self.ip, self.port) logging.debug("Sent VV_VP_ACK_FAILED message to conn:%s" % conn_id) self.sendMessage(message, conn) else: message = eVV_VP_ACK_FAILED(self.ip, self.port) logging.debug("Sent VV_VP_ACK_FAILED message to conn:%s" % conn_id) self.sendMessage(message, conn) def newSyncSession(self, conn, conn_id, vv_id): session = SyncSession(conn_id, conn, self, SYNC) self.sync.setSession(session, vv_id, self.ip, self.port) self.activeSessions[conn_id] = session message = eVV_SYNC_ACK(self.ip, self.port, vv_id) logging.debug("Sent VV_SYNC_ACK message to conn:%s" % conn_id) self.sendMessage(message, conn) def sendMessage(self, message, conn): self.cWriter.send(message, conn) def disconnection_polling(self, taskdata): if (self.cManager.resetConnectionAvailable()): connectionPointer = PointerToConnection() self.cManager.getResetConnection(connectionPointer) lostConnection = connectionPointer.p() for session in self.activeSessions.values(): if session.conn == lostConnection: logging.info("Lost Connection from ip:%s, conn:%s" % (session.client_address, session.conn_id)) conn_id = session.conn_id if session.getSessionType() == VP: cameras = session.getCameras() for cam_id in cameras: camera = self.cam_mgr.getCameraById(cam_id) camera.clearSession() del self.activeSessions[conn_id] del self.connection_map[conn_id] break self.cManager.closeConnection(lostConnection) return Task.cont def toggleInfo(self): if self.showing_info: self.info_label.hide() self.showing_info = False else: self.info_label.show() self.showing_info = True def exit(self): for connection in self.connection_map.values(): self.cReader.removeConnection(connection) self.cManager.closeConnection(self.tcpSocket) self.tcpSocket.getSocket().Close()
class Server(DirectObject): #----------------- # Initialization #----------------- def __init__(self): self.log = Log() self.log.Open('server.txt') self.activeClients = {} self.nextAvailablePid = 0 self.fsm = ServerFSM(self) self.fsm.request('LoadingEngine') self.heartbeat = Heartbeat() self.chat = ChatBox() taskMgr.doMethodLater(1, self.CheckForTimedOutClients, 'CheckForTimedOutClients') def CreateNetworkObjects(self): if(self.CreateUDPConnection() and self.CreateTCPConnection()): self.dataHandler = ServerDataHandler(self) self.reliablePacketController = ReliablePacketController(self.cWriter, self.conn, self.dataHandler, self.UDPPacketListenTask) self.unreliablePacketController = UnreliablePacketController(self.cWriter, self.conn, self.dataHandler) self.tcpPacketController = TCPPacketController(self.tcpWriter, self.tcpReader, self.cManager, self.dataHandler) self.dataHandler.SetPacketControllers(self.reliablePacketController, self.unreliablePacketController, self.tcpPacketController) self.ListenForIncomingTraffic() return True return False def CreateUDPConnection(self): self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.conn = self.cManager.openUDPConnection(Globals.PORT_SERVER_LISTENER) if(self.conn): self.log.WriteLine('Connection on %s okay.' % (Globals.PORT_SERVER_LISTENER)) else: self.log.WriteError('Connection on %s failed.' % (Globals.PORT_SERVER_LISTENER)) sys.exit() return False self.cReader.addConnection(self.conn) return True def CreateTCPConnection(self): self.tcpSocket = self.cManager.openTCPServerRendezvous(Globals.PORT_SERVER_LISTENER, 1000) self.tcpWriter = ConnectionWriter(self.cManager,0) self.tcpListener = QueuedConnectionListener(self.cManager, 0) self.tcpListener.addConnection(self.tcpSocket) self.tcpReader = QueuedConnectionReader(self.cManager, 0) return True def ListenForIncomingTraffic(self): taskMgr.add(self.UDPPacketListenTask, "UDPPacketListenTask") taskMgr.add(self.TCPConnectionListenTask, "TCPConnectionListenTask", -39) taskMgr.add(self.TCPPacketListenTask, "TCPPacketListenTask", -40) def StartBroadcastGameState(self): print 'StartBroadcastGameState' taskMgr.doMethodLater(Globals.SERVER_SEND_DELAY, self.BroadcastGameState, "BroadcastGameState") taskMgr.doMethodLater(2.0, self.BroadcastScoreboard, 'BroadcastScoreboard') #---------------------- # Listening for data #---------------------- def UDPPacketListenTask(self, task = None): while self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): data = PyDatagramIterator(datagram) ip = datagram.getAddress().getIpString() port = datagram.getAddress().getPort() peerAddr = NetAddress() peerAddr.setHost(ip, port) #print 'GOT UDP PACKET FROM', peerAddr.getIpString(), peerAddr.getPort() isReliable = data.getUint8() if(isReliable == Packet.PC_RELIABLE_PACKET): self.reliablePacketController.OnPacketReceived(data, peerAddr) elif(isReliable == Packet.PC_UNRELIABLE_PACKET): self.unreliablePacketController.OnPacketReceived(data, peerAddr) if(self.ClientIsConnected(peerAddr)): self.GetActiveClient(peerAddr).timestamp = GameTime.time return task.cont def TCPPacketListenTask(self, task): if self.tcpReader.dataAvailable(): datagram = NetDatagram() if self.tcpReader.getData(datagram): data = PyDatagramIterator(datagram) ip = datagram.getAddress().getIpString() port = datagram.getAddress().getPort() peerAddr = NetAddress() peerAddr.setHost(ip, port) packetType = data.getUint8() if(packetType == Packet.PC_TCP_PACKET): self.tcpPacketController.OnPacketReceived(data, peerAddr) return task.cont def TCPConnectionListenTask(self, task): if self.tcpListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.tcpListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.tcpReader.addConnection(newConnection) self.tcpPacketController.AddConnection(newConnection, netAddress) return task.cont def CheckForTimedOutClients(self, task): t = GameTime.GetTime() for ac in self.activeClients.values(): if(t - ac.timestamp > 2): print 'player timed out', t, ac.timestamp self.OnClientDisconnect(ac.peerAddr) self.chat.AddMessage('[Server]: ', Vec4(0.9, 0.9, 0.9, 1), '%s timed out' % (ac.name)) return task.again def IsFull(self): return len(self.activeClients) > Globals.MAX_PLAYERS def BroadcastScoreboard(self, task = None): self.dataHandler.BroadcastScoreboard(self.GetAllPeerAddrs(), self.engine.GetPlayerController().GetAllPlayerStates()) return Task.again def BroadcastGameState(self, task = None): peerAddrs = self.GetAllPeerAddrs() if(peerAddrs): self.dataHandler.BroadcastGameState(peerAddrs, self.engine.GetPlayerController().GetAllPlayerStates()) #self.game.ClearAllDeltaStates() if(self.engine.environment.HasChanged()): self.dataHandler.BroadcastEnvironmentChange(self.GetAllPeerAddrs(), self.engine.environment.GetDestroyedBlocks(), self.engine.environment.GetAddedBlocks()) self.engine.environment.ClearBlockNotifications() return Task.again def ClientIsConnected(self, peerAddr): return Packet.PeerAddrToIpPort(peerAddr) in self.activeClients.keys() def GetAllPeerAddrs(self): peerAddrs = [] for ac in self.activeClients.values(): if(ac.engineLoaded): peerAddrs.append(ac.peerAddr) return peerAddrs def SendPlayerDeath(self, playerState): peerAddrs = self.GetAllPeerAddrs() self.dataHandler.SendPlayerDeath(playerState, peerAddrs) def SendPlayerRespawn(self, playerState): peerAddrs = self.GetAllPeerAddrs() self.dataHandler.SendPlayerRespawn(playerState, peerAddrs) #----------------------------- # Handling data from clients #----------------------------- def OnEngineLoaded(self, peerAddr): if(self.ClientIsConnected(peerAddr)): ac = self.GetActiveClient(peerAddr) ac.timestamp = GameTime.GetTime() ac.engineLoaded = True self.dataHandler.SendListOfConnectedPlayers(peerAddr, self.engine.GetPlayerController().GetAllPlayerStates()) def OnTeamSelect(self, peerAddr, team): if(self.ClientIsConnected(peerAddr)): ac = self.GetActiveClient(peerAddr) self.engine.game.AddPlayerToTeam(self.GetPlayer(ac.pid), team) PlayerRespawnEvent(self.engine.playerController.GetPlayer(ac.pid), Point3(random.randint(0, 8), random.randint(0, 8), 50)).Fire() def AddClient(self, peerAddr, name): a = ActiveClient() a.peerAddr = peerAddr a.pid = self.GetNextPid() a.name = name self.activeClients[Packet.PeerAddrToIpPort(peerAddr)] = a self.engine.GetPlayerController().AddNewPlayer(pid = a.pid, teamId = Game.SPECTATE, name = name) self.reliablePacketController.CreatePeerData(peerAddr) self.reliablePacketController.SetCurrentPeer(peerAddr) # self.reliablePacketController.AddRecvdSeqNum() # self.reliablePacketController.currentPeer.mostRecentSeqRecvd = 1 Globals.CURRENT_PLAYERS = len(self.activeClients) return a.pid def OnClientChatMessage(self, messageType, message, peerAddr): peerAddrs = [] for ac in self.activeClients.values(): if(ac.engineLoaded): peerAddrs.append(ac.peerAddr) if(self.ClientIsConnected(peerAddr)): print 'message', message if(message.startswith('/')): if(message[1:] == 'save'): self.engine.SaveEnvironment() self.dataHandler.SendChatMessage(ChatBox.TYPE_CONSOLE, 255, 'Saving Environment...', peerAddrs) return pid = self.activeClients[Packet.PeerAddrToIpPort(peerAddr)].pid self.dataHandler.SendChatMessage(messageType, pid, message, peerAddrs) def OnClientDisconnect(self, peerAddr): if(self.ClientIsConnected(peerAddr)): pid = self.activeClients[Packet.PeerAddrToIpPort(peerAddr)].pid self.engine.GetPlayerController().RemovePlayer(pid) self.RemovePeer(peerAddr) self.dataHandler.SendPlayerDisconnect(pid, self.GetAllPeerAddrs()) self.engine.SaveEnvironment() Globals.CURRENT_PLAYERS = len(self.activeClients) def OnClientItemChange(self, peerAddr, itemId, extraData): pid = self.GetActiveClient(peerAddr).pid player = self.GetPlayer(pid) print 'server item change', player, itemId self.engine.GetPlayerController().OtherPlayerItemChange(player, itemId, extraData) def RemovePeer(self, peerAddr): self.reliablePacketController.RemovePeerData(peerAddr) self.unreliablePacketController.RemovePeerData(peerAddr) if(self.ClientIsConnected(peerAddr)): del self.activeClients[Packet.PeerAddrToIpPort(peerAddr)] def ProcessClientInput(self, peerAddr, keys, lookingDir, clicks, timestamp): if(self.ClientIsConnected(peerAddr)): pid = self.GetActiveClient(peerAddr).pid self.engine.GetPlayerController().QueueClientInput(self.GetPlayer(pid), keys, lookingDir, clicks, timestamp) def SetLastClientTimestamp(self, peerAddr, timestamp): if(self.ClientIsConnected(peerAddr)): self.GetActiveClient(peerAddr).timestamp = timestamp def GetEnvironment(self): return self.engine.environment def GetNextPid(self): self.nextAvailablePid += 1 return self.nextAvailablePid def GetPlayer(self, pid): return self.engine.GetPlayerController().GetPlayer(pid) def GetName(self, peerAddr): if(self.ClientIsConnected(peerAddr)): return self.GetActiveClient(peerAddr).name else: return 'NOT A PLAYER' def GetActiveClient(self, peerAddr): return self.activeClients[Packet.PeerAddrToIpPort(peerAddr)] def Exit(self): self.log.Close()
class LoginServer(ShowBase): def __init__(self, port, backlog = 1000, compress = False): ShowBase.__init__(self) self.compress = compress self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.clientdb = ClientDataBase() if not self.clientdb.connected: self.clientdb = None print 'Login Server failed to start...' else: # This is for pre-login self.tempConnections = [] # This is for authed clients self.activeClients = [] # This is for authed servers self.activeServers = [] # This is for authed chat servers self.activeChats = [] self.connect(port, backlog) self.startPolling() self.taskMgr.doMethodLater(0.5, self.lobbyLoop, 'Lobby Loop') print 'Login Server operating...' def connect(self, port, backlog = 1000): # Bind to our socket tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(tcpSocket) def startPolling(self): self.taskMgr.add(self.tskListenerPolling, "serverListenTask", -40) self.taskMgr.add(self.tskDisconnectPolling, "serverDisconnectTask", -39) def tskListenerPolling(self, task): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.tempConnections.append(newConnection) self.cReader.addConnection(newConnection) return Task.cont def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable() == True: connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection self.cReader.removeConnection(connection) # Check for if it was a client for client in self.activeClients: if client.connection == connection: print 'removing client' self.activeClients.remove(client) break # then check servers for server in self.activeServers: if server.connection == connection: self.activeServers.remove(server) break # then check servers for chat in self.activeChats: if chat.connection == connection: self.activeChats.remove(chat) break return Task.cont def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def encode(self, data, compress = False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data, con): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, con) # This will check and do the logins. def auth(self, datagram): # If in login state. con = datagram.getConnection() package = self.processData(datagram) if len(package) == 2: if package[0] == 'create': success, result = self.clientdb.addClient(package[1][0], package[1][1]) if success: self.sendData(('createSuccess', result), con) else: self.sendData(('createFailed', result), con) return False if package[0] == 'client': userFound = False for client in self.activeClients: if client.name == package[1][0]: userFound = True self.sendData(('loginFailed', 'logged'), con) break if not userFound: valid, result = self.clientdb.validateClient(package[1][0], package[1][1]) if valid: self.activeClients.append(Client(package[1][0], con)) self.sendData(('loginValid', result), con) return True else: self.sendData(('loginFailed', result), con) return False # if server add it to the list of current active servers if package[0] == 'server': self.activeServers.append(Server(package[1], con)) return True # if server add it to the list of current active servers if package[0] == 'chat': self.activeChats.append(Chat(package[1], con)) return True def getData(self): data = [] while self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): if datagram.getConnection() in self.tempConnections: if self.auth(datagram): self.tempConnections.remove(datagram.getConnection()) continue # Check if the data recieved is from a valid client. for client in self.activeClients: if datagram.getConnection() == client.connection: data.append(('client', self.processData(datagram), client)) break # Check if the data recieved is from a valid server. for server in self.activeServers: if datagram.getConnection() == server.connection: data.append(('server', self.processData(datagram), server)) break # Check if the data recieved is from a valid chat. for chat in self.activeChats: if datagram.getConnection() == chat.connection: data.append(('chat', self.processData(datagram), chat)) break return data # handles new joining clients and updates all clients of chats and readystatus of players def lobbyLoop(self, task): # if in lobby state temp = self.getData() if temp != []: for package in temp: # handle client incoming packages here if package[0] == 'client': # This is where packages will come after clients connect to the server # will be things like requesting available servers and chat servers if package[1] == 'server_query': for server in self.activeServers: if server.state == 'lobby': self.sendData( ('server', (server.name, str(server.connection.getAddress()))), package[2].connection) self.sendData( ('final', 'No more servers'), package[2].connection) # handle server incoming packages here elif package[0] == 'server': # auth # game state change if len(package[1]) == 2: if package[1][0] == 'auth': clientAuth = False print 'Attempting Authentication on: ', package[1][1] for client in self.activeClients: if client.name == package[1][1]: clientAuth = True break if clientAuth: self.sendData(('auth', client.name), package[2].connection) else: self.sendData(('fail', package[1][1]), package[2].connection) elif package[1][0] == 'state': package[2].state = package[1][1] # handle chat server incoming packages here elif package[0] == 'chat': print 'Authorized chat server sent package' # handle packages from the chat servers # like making public/private # authing clients return task.again