def onConnect(self): """ Handler called on network connection. """ if self.verbose: log.info( "[HAPPYBOOM] Connected to server, send presentation connection()." ) self.launchEvent("happyboom", "connection", self._io)
def __processNewPacket(self, packet): """ Do something with a new packet @type packet: C{L{Packet}} """ if self.verbose: log.info("New udp message : %s" % packet) if self.on_new_packet != None: self.on_new_packet(packet)
def removeClient(self, ioclient): if self.__verbose: log.info("Disconnect client %s." % ioclient) self.gateway.sendText(u"Client %s leave us." % ioclient) self.__clients_lock.acquire() del self.__clients[ioclient.addr] self.__clients_lock.release()
def onClientFeatures(self, ioclient, features): # Register client in the clients list client = Client(ioclient, self.gateway, self) self.__clients_lock.acquire() self.__clients[client.addr] = client self.__clients_lock.release() # Register client to features for feature in features: f = self.__protocol[ord(feature)] feature = f.name if self.__verbose: log.info("Register feature %s for client %s" % (feature, client)) if feature in self.__supported_features: self.__supported_features[feature].append(ioclient) else: self.__supported_features[feature] = [ioclient] client.features.append(feature) # Send message to network and to the log txt = u"Welcome to new (display) client : %s" % client log.info("[*] Client %s connected" % client) self.launchEvent("happyboom", "network", "info", "notice", txt) self.launchEvent("happyboom", "newClient", client)
def live(self): """ Keep the connection alive : Resend packet if needed, clean old received packets, send ping if needed. """ # Resend packet which don't have received their ack yet self.__waitAck_sema.acquire() waitAckCopy = self.__waitAck.copy() self.__waitAck_sema.release() for id, packet in waitAckCopy.items(): if packet.timeout < time.time(): if packet.sent < io.Packet.max_resend: self.send(packet) else: self.io.clientLostConnection(self) # Clean old received packets self.__received_sema.acquire() receivedCopy = self.__received.copy() self.__received_sema.release() for id, timeout in receivedCopy.items(): if timeout < time.time(): if self.io.debug: log.info("Remove old packet %u from %s:%u (clear cache)." \ % (id, self.host, self.port)) self.__received_sema.acquire() del self.__received[id] self.__received_sema.release() # Send ping if needed if self.send_ping: self.__pinger.live()
def __processPacket(self, packet): client = packet.recv_from if self.debug: log.info("Received packet %s from %s:%u" % (packet, client.host, client.port)) # Send an ack if needed if not packet.skippable: self.__sendAck(packet) # Is is a special packet (ack / ping / poing) ? if packet.type == Packet.PACKET_ACK: client.processAck(packet) return None if packet.type == Packet.PACKET_PING: client.processPing(packet) return None if packet.type == Packet.PACKET_PONG: client.processPong(packet) return None # This packet is already received ? Drop it! if client.alreadyReceived(packet.id): if self.debug: log.warning("Drop packet %u (already received)" % packet.id) return None client.receivePacket(packet) # Returns the new packet return packet
def evt_happyboom_network(self, feature, event, *args): try: if self.debug: log.info("Send event: %s.%s%s" % (feature, event, args)) self.launchEvent("happyboom", "event", (self._io,), feature, event, args) except ProtocolException, msg: log.error("Protocol error: %s" % msg)
def stop(self): """ Stops the game client.""" if self.__verbose: log.info("[BOOMBOOM] Stopping client...") Happyboom.stop(self) self.launchEvent("happyboom", "disconnection", self._io, u"Quit.") self.display.stop()
def connect(self, host, port): """ Connect to host:port """ max_connection = 50 self.__addr = (host, port,) if self.__is_server: if self.verbose: log.info("Run server at %s:%u (tcp)" % (self.host, self.port)) thread.start_new_thread( self.__waiter.runThread, (port,max_connection,)) else: if self.verbose: log.info("Connect to server %s:%u" % (self.host, self.port)) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: s.connect(self.__addr) except socket.error, err: if err[0]==111: if self.verbose: log.warning("Fail to connect to server %s:%u" % (self.host, self.port)) if self.on_connection_fails: self.on_connection_fails() return raise client = TCP_Client(self, self.__addr, socket=s) self.__server = client self.__clients_sema.acquire() self.__clients[client.addr] = client self.__clients_sema.release()
def live(self): """ Keep the connection alive : Resend packet if needed, clean old received packets, send ping if needed. """ # Resend packet which don't have received their ack yet self.__waitAck_sema.acquire() waitAckCopy = self.__waitAck.copy() self.__waitAck_sema.release() for id,packet in waitAckCopy.items(): if packet.timeout < time.time(): if packet.sent < io.Packet.max_resend: self.send(packet) else: self.io.clientLostConnection(self) # Clean old received packets self.__received_sema.acquire() receivedCopy = self.__received.copy() self.__received_sema.release() for id,timeout in receivedCopy.items(): if timeout < time.time(): if self.io.debug: log.info("Remove old packet %u from %s:%u (clear cache)." \ % (id, self.host, self.port)) self.__received_sema.acquire() del self.__received[id] self.__received_sema.release() # Send ping if needed if self.send_ping: self.__pinger.live()
def evt_happyboom_network(self, feature, event, *args): try: if self.debug: log.info("Send event: %s.%s%s" % (feature, event, args)) self.launchEvent("happyboom", "event", (self._io, ), feature, event, args) except ProtocolException, msg: log.error("Protocol error: %s" % msg)
def clientConnect(self, client): if self.__server.debug: log.info("Client %s enter server %s." \ % (client.name, self.__server.name)) self.__nb_clients_sema.acquire() self.__nb_clients = self.__nb_clients + 1 self.__nb_clients_sema.release() self.__server.clientConnect(client)
def closeClient(self, ioclient): # TODO: get client of type Client for the client of type ClientIO to send # him bye # client.sendNetMsg("presentation", "bye", "utf8", u"Lost connection") client = self.getClientByAddr(ioclient.addr) if client == None: return log.info("[*] Client %s leave us." % client) self.removeClient(ioclient)
def clientDisconnect(self, client): if self.verbose: log.info("Client %s leave server %s." % (client, self)) self.__clients_sema.acquire() self.__clients.remove(client) self.__clients_sema.release() self.__waiter.client_disconnect(client) if self.on_client_disconnect != None: self.on_client_disconnect (client)
def disconnectClient(self, client): """ Disconnect a client. """ self.__clients_sema.acquire() if self.__clients.has_key(client.addr): del self.__clients[client.addr] self.__clients_sema.release() if self.verbose: log.info("Disconnect client %s." % client) if self.on_client_disconnect != None: self.on_client_disconnect (client) if self.__server == client: self.disconnect()
def disconnectClient(self, client): """ Disconnect a client. @type client: C{L{IO_Client<io.IO_Client>}} """ self.__clients_sema.acquire() if self.__clients.has_key(client.addr): del self.__clients[client.addr] self.__clients_sema.release() if self.verbose: log.info("Disconnect client %s." % client) if self.on_client_disconnect != None: self.on_client_disconnect(client)
def sendBinary(self, data, client): """ Send binary data that doesn't need an acknoledge. @type data: C{str} @type client: C{L{IO_Client<io.IO_Client>}} """ if self.debug: log.info("Send data %s to %s (without ack)" % (data, client)) self.__socket.sendto(data, client.addr) # Call user event if needed if self.on_send != None: self.on_send(data)
def stop(self): self.__stoplock.acquire() if self.__stopped: self.__stoplock.release() return self.__stopped = True self.__stoplock.release() if self.__verbose: log.info("[*] Stopping server...") self.__client_manager.stop() self.__gateway.stop() log.info("[*] Server stopped")
def start(self): HBGateway.start(self) if self._verbose: log.info("[*] Creating agents") self.addAgent(LogAgent(self, debug=self._debug)) self.addAgent(Game(self, debug=self._debug)) self.addAgent(World(self, debug=self._debug)) self.addAgent(Character(self, 100, 1, debug=self._debug)) self.addAgent(Character(self, -150, 2, debug=self._debug)) self.addAgent(Weapon(self, debug=self._debug)) self.addAgent(Projectile(self, debug=self._debug)) self.sendBroadcastMessage(Message("start", ()), "game")
def onClientConnection(self, ioclient, version, signature): # TODO: Case where signature != "" ??? (reconnection) if self.__verbose: log.info("Client %s try to connect : check version." % ioclient) server_version = self.__protocol.version if version == server_version: if self.__verbose: log.info("Client %s try to connect: version ok." % ioclient) signature = self.generateSignature(ioclient) self.launchEvent("happyboom", "connection", ioclient, server_version, signature) else: if self.__verbose: log.warning("Client %s try to connect: wrong version (%s)." % version) self.launchEvent("happyboom", "closeConnection", ioclient, u"Wrong server version (%s VS %s)" % (version, serveur_version))
def start(self): if self.__verbose: log.info("[*] Starting server") self.__io.name = "server" self.__io.on_client_connect = self.openClient self.__io.on_client_disconnect = self.closeClient self.__io.on_new_packet = self.presentation.processPacket self.__io.connect('', self.client_port) self.launchEvent("happyboom", "register", "connection", self.onClientConnection) self.launchEvent("happyboom", "register", "disconnection", self.onClientDisconnection) self.launchEvent("happyboom", "register", "features", self.onClientFeatures) thread.start_new_thread(self.run_io_thread, ())
def evt_happyboom_connection(self, ioclient, version=None, signature=""): """ Send a connection message to ioclient. @type version: str @type signature: str """ if version == None: version = self.protocol.version if self.verbose: log.info("[PRESENTATION] Send connection(\"%s\", \"%s\")" % (version, signature)) data = self.packConnection(version, signature) ioclient.send( Packet(data) )
def __processData(self, client, data): while data != "": packet = Packet() packet.recv_from = client data = packet.unpack(data) if not packet.isValid(): if self.debug: log.warning("Received buggy network packet from %s!" % client) return if self.debug: log.info("Received %s:%u => \"%s\"" % (client.host, client.port, packet.data)) if self.on_new_packet: self.on_new_packet(packet)
def evt_happyboom_disconnection(self, ioclient, reason): """ Send a disconnection message to ioclient. @type ioclient: L{IOClient} @type reason: unicode """ if self.verbose: log.info(u"[PRESENTATION] Send disconnection(\"%s\")" % reason) data = self.packDisconnection(reason) ioclient.send( Packet(data) ) ioclient.disconnect()
def evt_happyboom_disconnection(self, ioclient, reason): """ Send a disconnection message to ioclient. @type ioclient: L{IOClient} @type reason: unicode """ if self.verbose: log.info(u"[PRESENTATION] Send disconnection(\"%s\")" % reason) data = self.packDisconnection(reason) ioclient.send(Packet(data)) ioclient.disconnect()
def start(self): """ Starts the client : connection to the server, etc. """ # Try to connect to server if self.verbose: log.info("[HAPPYBOOM] Trying to connect to server %s:%u" % (self.host, self.port)) self._io.on_connect = self.onConnect self._io.on_connection_fails = self.onConnectionFails self._io.on_disconnect = self.onDisconnect self._io.on_new_packet = self.presentation.processPacket self._io.on_lost_connection = self.onLostConnection self._io.connect(self.host, self.port) if not self._io.is_ready: return thread.start_new_thread(self._io.run_thread, ())
def start(self): """ Starts the game client.""" if self.__verbose: log.info("[BOOMBOOM] Starting client...") Happyboom.start(self) # Create thread for display thread.start_new_thread(self.displayThread, ()) quit = False while not quit: self.input.process() time.sleep(0.100) quit = self.stopped
def evt_happyboom_connection(self, ioclient, version=None, signature=""): """ Send a connection message to ioclient. @type version: str @type signature: str """ if version == None: version = self.protocol.version if self.verbose: log.info("[PRESENTATION] Send connection(\"%s\", \"%s\")" % (version, signature)) data = self.packConnection(version, signature) ioclient.send(Packet(data))
def stop(self): """ Stops the display client : disconnection from the server, etc. """ # Does not stop several times self.__stoplock.acquire() if self.__stopped: self.__stoplock.release() return False self.__stopped = True self.__stoplock.release() self._io.stop() if self.verbose: log.info("[HAPPYBOOM] Stopped") return True
def __sendDataTo(self, packet, data, client, need_ack): """ Send binary data with an acknoledge to a client. @type data: C{str} @type client: C{L{IO_Client<io.IO_Client>}} @type need_ack: C{bool} """ if self.debug: log.info("Send packet %s to %s" % (packet, client)) self.__socket.sendto(data, client.addr) # If the packet need an ack, add it to the list if need_ack: client.needAck(packet) # Call user event if needed if self.on_send != None: self.on_send(data)
def start(self, port, max_connection): self.__max_clients = max_connection self.__port = port if self.__server.debug: log.info("Start %s on port %u." \ % (self.__server.name, port)) self.__socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: self.__socket.bind((self.__host, self.__port)) self.__socket.listen(max_connection) except socket.error, err: if self.__server.debug: log.error("Binding error for %s." % (self.__server.name)) if self.__server.on_binding_error != None: self.__server.on_binding_error(self.__server) return
def start(self): if self.__verbose: log.info("[*] Starting server...") self.__gateway.start() self.__client_manager.start() log.info("[*] Server started") self.__stoplock.acquire() running = not self.__stopped self.__stoplock.release() while running: self.__gateway.process() self.__client_manager.process() time.sleep(0.01) self.__stoplock.acquire() running = not self.__stopped self.__stoplock.release()
def onClientConnection(self, ioclient, version, signature): # TODO: Case where signature != "" ??? (reconnection) if self.__verbose: log.info("Client %s try to connect : check version." % ioclient) server_version = self.__protocol.version if version == server_version: if self.__verbose: log.info("Client %s try to connect: version ok." % ioclient) signature = self.generateSignature(ioclient) self.launchEvent("happyboom", "connection", ioclient, server_version, signature) else: if self.__verbose: log.warning("Client %s try to connect: wrong version (%s)." % version) self.launchEvent( "happyboom", "closeConnection", ioclient, u"Wrong server version (%s VS %s)" % (version, serveur_version))
def connect(self, host, port): """ Connect to host:port @type host: C{str} @type port: C{int} """ if host != "": host = socket.gethostbyname(host) else: host = "127.0.0.1" self.__addr = ( host, port, ) self.__socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) if self.__is_server: if self.verbose: log.info("Run server on port %u (udp)." % self.port) self.__socket.bind(( "", port, )) else: if self.verbose: log.info("Connect to server %s:%u." % (self.host, self.port)) self.__server = UDP_Client(self, self.__addr) self.__server.name = "server" self.__server.send_ping = True self.__clients_sema.acquire() self.__clients[self.__addr] = self.__server self.__clients_sema.release() self.__socket_open = True self.__socket.setblocking(0) if not self.__is_server: self.send(Packet("I'm here")) BaseIO.connect(self, host, port) # Call user event if needed if self.on_connect != None: self.on_connect()
def main(): # Add HappyBoom to PYTHONPATH import sys, os file_dir = os.path.dirname(__file__) happyboomdir = os.path.join(file_dir, "..", "happyboom", "trunk") sys.path.append(happyboomdir) # Get user directory from happyboom.common.file import getCreateHomeDir logdir = getCreateHomeDir("boomboom") # Setup log filename from happyboom.common.log import log if logdir != None: logname = os.path.join(logdir, "server-log") log.setFilename(logname) # Read command line arguments val = { \ "input_port": 12430, "max_clients": 4, "verbose": False, "debug": False} arg = parseArgs(val) # Create BoomBoom server from server.bb_server import Server from happyboom.common.protocol import loadProtocol protocol = loadProtocol("protocol.xml") server = Server(protocol, arg) # Main loop try: server.start() except KeyboardInterrupt: log.info("Program interrupted (CTRL+C).") pass # Stop the server server.stop()
def __processRecvData(self, data, addr): if self.__is_server: self.__clients_sema.acquire() if addr not in self.__clients: client = UDP_Client(self, addr) self.__clients[addr] = client self.__clients_sema.release() if self.verbose: log.info("New client: %s:%u." % (addr[0], addr[1])) client.send_ping = True if self.on_client_connect != None: self.on_client_connect(client) else: client = self.__clients[addr] self.__clients_sema.release() else: # Drop packets which doesn't come from server if self.__server.addr != addr: if self.debug: log.warning( "Drop packet from %s:%u (it isn't the server address)." % (addr[0], addr[1])) return None client = self.__server # Call user event if needed if self.on_receive != None: self.on_receive(data) # Decode data to normal packet (unpack) packet = Packet() packet.unpack(data) if not packet.isValid(): if self.debug: log.warning("Drop invalid network packet from %s" % (data, client)) return None # Return packet packet.recv_from = client return self.__processPacket(packet)
def processAck(self, packet): """ Process new received acknoledge. @type packet: C{L{Packet<io.Packet>}} """ # Read packet ID format = "!I" if len(packet.data) != struct.calcsize(format): return None data = struct.unpack(format, packet.data) id = data[0] # Packet still exists ? self.__waitAck_sema.acquire() if not self.__waitAck.has_key(id): self.__waitAck_sema.release() return # Debug message if self.io.debug: t = time.time() - self.__waitAck[id].creation log.info("Ack %u received (time=%.1f ms)" % (id, t*1000)) # The packet don't need ack anymore del self.__waitAck[id] self.__waitAck_sema.release()
def main(): # Add HappyBoom to PYTHONPATH ("../" today, but should be improved) import sys, os file_dir = os.path.dirname(__file__) happyboomdir = os.path.join(file_dir, "../happyboom/trunk") sys.path.append(happyboomdir) # Get user directory from happyboom.common.file import getCreateHomeDir logdir = getCreateHomeDir("boomboom") # Setup log filename from happyboom.common.log import log if logdir != None: logname = os.path.join(logdir, "client-log") log.setFilename(logname) # Read command line arguments val = { "host": "127.0.0.1", \ "port": 12430, \ "max_fps": 50, \ "verbose": False, \ "textmode": False, \ "server-log": False, \ "name": "-", \ "debug": False, \ "item_path": "client/items"} arg = parseArgs(val) textmode = arg["textmode"] # Create the client if not textmode: log.info("Start client with pygame.") import pygame pygame.init() from client import Client run(Client, arg) pygame.quit() else: log.info("Start client with curses.") import curses curses.wrapper(run_curses, arg) log.use_print = True log.info("Quit.")
def main(): global log # Initialize the application init() # Create the server from server.hw_server import HappyWarryServer server = HappyWarryServer() # Run the server try: log.info(_("Server started.")) server.run() except KeyboardInterrupt: log.info(_("Program interrupted (CTRL+C).")) server.stop() log.info(_("Server quit."))
def openClient(self, ioclient): if self.__verbose: log.info("[*] Client %s try to connect ..." % ioclient)
def onClientDisconnection(self, ioclient, reason): log.info("Client %s leave us: %s" % (ioclient, reason)) self.closeClient(ioclient)
def evt_log_error(self, text): log.info(u"[Server Log][err!] %s" % text)
def evt_log_warning(self, text): log.info(u"[Server Log][warn] %s" % text)
def evt_log_info(self, text): log.info(u"[Server Log][info] %s" % text)
def onDisconnect(self): """ Handler called on network disconnection. """ if self.stopped: return log.info("[HAPPYBOOM] Connection to server closed") self.launchEvent("happyboom", "stop")
def onConnect(self): """ Handler called on network connection. """ if self.verbose: log.info("[HAPPYBOOM] Connected to server, send presentation connection().") self.launchEvent("happyboom", "connection", self._io)
def netCreateItem(self, client): if self.type in client.features: self.launchEvent("happyboom", "netCreateItem", client, self) elif self.__debug: log.info("Client %s doesn't want item %s" % (client, self.type))
def recvNetMsg(self, ioclient, feature, event, args): if self._verbose: log.info("Received: %s.%s%s" % (feature, event, args)) message = Message("%s_%s" % (feature, event), args) self.sendBroadcastMessage(message, "%s_listener" % feature)
def processEvent(self, ioclient, feature, event, args): if self.debug: log.info("New event: %s.%s%s" % (feature, event, args)) assert feature in self.features, "Unexpected feature" self.launchEvent(feature, event, *args)