home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / gnome-games / games-server.py
Encoding:
Python Source  |  2006-08-22  |  5.2 KB  |  172 lines

  1. #!/usr/bin/python
  2.  
  3. import select
  4. import socket
  5. import errno
  6. import traceback
  7. import fcntl
  8. import os
  9. import sys
  10. import threading
  11. from sys import stdin, stdout, stderr
  12. from threading import Thread
  13.  
  14. class Client:
  15.     WAITING = 1
  16.     PARTNERED = 2
  17.     DEAD = 3
  18.  
  19.     def __repr__(self):
  20.         return "<Client instance at 0x%s: %s / %s / %s / %s>" % (hex(id(self)),
  21.                                                             self.sock.fileno(), self.state, self.evmask, len(self.outbuf))
  22.  
  23.     def __init__(self, server, sock):
  24.         self.outbuf = ""
  25.         self.sock = sock
  26.         self.server = server
  27.         self.partner = None
  28.         self.state = self.WAITING
  29.         self.evmask = 0
  30.  
  31.     def destroy(self):
  32.         self.state = self.DEAD
  33.         partner = self.partner
  34.         self.partner = None
  35.         if partner:
  36.             self.server.del_client(partner)
  37.         self.sock.close()
  38.  
  39.     def set_partner(self, partner):
  40.         self.partner = partner
  41.         self.state = self.PARTNERED
  42.         self.register()
  43.  
  44.     def register(self):
  45.         evmask = select.POLLHUP|select.POLLNVAL|select.POLLERR
  46.         if self.state == self.PARTNERED:
  47.             evmask = evmask | select.POLLIN
  48.         if len(self.outbuf):
  49.             evmask = evmask | select.POLLOUT
  50.         if self.evmask != evmask:
  51.             self.server.poller.register(self.sock.fileno(), evmask)
  52.             self.evmask = evmask
  53.  
  54.     def write_val(self, val):
  55.         self.outbuf += val
  56.         self.register()
  57.  
  58.     def handle_write(self):
  59.         try:
  60.             n = self.sock.send(self.outbuf)
  61.         except (IOError, OSError, socket.error):
  62.             return self.server.del_client(self)
  63.         if n <= 0:
  64.             return self.server.del_client(self)
  65.         self.outbuf = self.outbuf[n:]
  66.         self.register()
  67.  
  68.     def handle_read(self):
  69.         assert self.state == self.PARTNERED
  70.         try:
  71.             data = self.sock.recv(8192)
  72.         except (IOError, OSError, socket.error):
  73.             return self.server.del_client(self)
  74.         if not len(data):
  75.             return self.server.del_client(self)
  76.         self.partner.write_val(data)
  77.  
  78. class Server(Thread):
  79.     def __init__(self, game_port):
  80.     Thread.__init__(self)
  81.         self.poller = select.poll()
  82.         self.asock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
  83.         self.asock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  84.         self.asock.bind(('', game_port))
  85.         self.asock.listen(10)
  86.     print "Game service running on port" , game_port
  87.     
  88.         self.cnxlist = {}
  89.         self.waitlist = []
  90.         self.ccount = 0
  91.  
  92.         self.poller.register(self.asock.fileno(), select.POLLIN)
  93.  
  94.     def run(self):
  95.         while 1:
  96.             try:
  97.                 evs = self.poller.poll()
  98.             except select.error, e:
  99.                 if e[0] == errno.EINTR:
  100.                     continue
  101.             for I in evs:
  102.                 if I[0] == self.asock.fileno():
  103.                     csock, addr = self.asock.accept()
  104.                     fcntl.fcntl(csock.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
  105.                     print "\nNew connection from %s, waitlist has %d items" % (addr, len(self.waitlist))
  106.                     cli = Client(self, csock)
  107.                     self.cnxlist[csock.fileno()] = cli
  108.                     self.waitlist.append(cli)
  109.                     self.ccount += 1
  110.                     cli.register()
  111.                 else:
  112.                     if not self.cnxlist.has_key(I[0]):
  113.                         assert 0, "Maybe something is broken with FD %s" % I[0]
  114.                         continue
  115.                     cnx = self.cnxlist[I[0]]
  116.                     if (I[1] & (select.POLLHUP|select.POLLNVAL|select.POLLERR)):
  117.                         self.del_client(cnx)
  118.                     else:
  119.                         if (I[1] & select.POLLIN):
  120.                             cnx.handle_read()
  121.                         if cnx.state != cnx.DEAD and (I[1] & select.POLLOUT):
  122.                             cnx.handle_write()
  123.             while len(self.waitlist) >= 2:
  124.                 c1 = self.waitlist[0]
  125.                 c2 = self.waitlist[1]
  126.                 self.waitlist = self.waitlist[2:]
  127.                 c1.write_val("set_peer 1\n") # First in line gets to move first :)
  128.                 c2.write_val("set_peer 31\n")
  129.                 c1.set_partner(c2)
  130.                 c2.set_partner(c1)
  131.  
  132.     def del_client(self, cli):
  133.         if cli.state == cli.DEAD:
  134.             return
  135.  
  136.         del self.cnxlist[cli.sock.fileno()]
  137.         self.poller.unregister(cli.sock.fileno())
  138.         cli.destroy()
  139.         if cli in self.waitlist:
  140.             self.waitlist.remove(cli)
  141.         self.ccount -= 1
  142.  
  143. # This is minimal code to make the process a daemon in the Unix
  144. # environment. See W. R. Stevens "Advanced Programming in the Unix
  145. # Environment". See chapter 13, esp. section 13.3
  146.  
  147. pid = os.fork ()
  148. if (pid != 0):  
  149.     os._exit (0)
  150. os.setsid ()
  151. os.chdir ("/")
  152.  
  153. for fd in range (0, os.sysconf ("SC_OPEN_MAX")):
  154.     try:
  155.         os.close (fd)
  156.     except:
  157.         pass
  158.  
  159. open ("/dev/null", "r")   # new stdin
  160. open ("/dev/null", "rw")  # new stdout
  161. open ("/dev/null", "rw")  # new stderr
  162.  
  163. # Create the servers - one for each game
  164. iagno1 = Server(26478)
  165. gnibbles1 = Server(26479)
  166.  
  167. # Start the servers
  168. iagno1.start()
  169. gnibbles1.start()
  170.  
  171.  
  172.