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 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): 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 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 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(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 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 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 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 disconnect(self): # Connect to our host's socket self.cManager.closeConnection(self.myConnection) self.connected = False # 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 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 disconnect(self): # Connect to our host's socket self.cManager.closeConnection(self.myConnection) self.connected = False # 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 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 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()