Advertisement
Guest User

Untitled

a guest
Aug 12th, 2010
279
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.36 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. from subprocess import Popen, PIPE
  4. import ConfigParser
  5. import os
  6. import socket
  7. import select
  8. import sys
  9. import time
  10. import string
  11. from StringIO import StringIO
  12.  
  13. default_config = """
  14. [remote]
  15. port = 9001
  16. password = bobblefish
  17. listenaddr = 127.0.0.1
  18.  
  19. [java]
  20. server   = ./minecraft_server.jar
  21. heap_max = 1024M
  22. heap_min = 1024M
  23. """
  24.  
  25. class Mineremote:
  26.    def __init__(self):
  27.       self.log('Hello, world!')
  28.  
  29.       if not self.load_config():
  30.          self.log('Failed loading the configuration file, this is fatal.')
  31.          exit()
  32.       else:
  33.          self.log('Loaded configuration!')
  34.          self.start_listening()
  35.  
  36.       try:
  37.          self.start_minecraft_server()
  38.          self.mainloop()
  39.       except Exception, e:
  40.          self.log_exception("__init__() -> mainloop()", e)
  41.       except KeyboardInterrupt:
  42.          self.log('Ctrl-C? Really! Maaaaaan...')
  43.          self.server_stdin.write('stop\n')
  44.  
  45.       self.log('Exit!')
  46.  
  47.    def log(self, msg):
  48.       print '[REMOTE] %s' % msg
  49.  
  50.    def log_server(self, msg):
  51.       print '[SERVER] %s' % msg
  52.  
  53.    def log_exception(self, function, exception):
  54.       self.log('-----------------------')
  55.       self.log('Caught exception!')
  56.       self.log('Function: %s' % function)
  57.       self.log('Exception: %s' % exception)
  58.       self.log('-----------------------')
  59.  
  60.    def start_listening(self):
  61.       self.log('Starting to listen on port %d...' % self.port)
  62.       self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  63.       self.server_socket.bind((self.listenaddr, self.port))
  64.       self.server_socket.listen(10)
  65.  
  66.    def clear_peer(self, peer):
  67.       try:
  68.          self.clients.pop(peer)
  69.          self.outputs.remove(peer)
  70.          peer.close()
  71.  
  72.          self.log('Connection count: %d' % len(self.clients))
  73.       except Exception, e:
  74.          self.log_exception('clear_peer()', e)
  75.  
  76.    def mainloop(self):
  77.       self.clients = dict({})
  78.  
  79.       while True:
  80.          try:
  81.             readready, writeready, exceptready = select.select(
  82.                   self.outputs,
  83.                   self.inputs,
  84.                   [],
  85.                   1.0)
  86.          except Exception, e:
  87.             self.log_exception("mainloop() > select()", e)
  88.             continue
  89.  
  90.          if readready == []:
  91.             for i in self.clients:
  92.                if (time.time() - self.clients[i]['connected']) > 15 \
  93.                      and not self.clients[i]['auth']:
  94.                   self.log('Killed %s:%s: No password within 15 seconds'
  95.                         % socket.getnameinfo(i.getpeername(), 0))
  96.                   self.clear_peer(i)
  97.                   break
  98.          else:
  99.             for s in readready:
  100.                if s == sys.stdin:
  101.                   line = s.readline()
  102.                   self.server_stdin.write('%s' % line)
  103.  
  104.                elif s == self.server_socket:
  105.                   (client, address) = self.server_socket.accept()
  106.                   self.outputs.append(client)
  107.  
  108.                   if self.password:
  109.                      auth = False
  110.                   else:
  111.                      auth = True
  112.  
  113.                   self.clients[client] = dict(
  114.                            {
  115.                               'socket': client,
  116.                               'auth': auth,
  117.                               'connected': int(time.time())
  118.                            }
  119.                         )
  120.    
  121.                   self.log('Got a new connection from %s:%s'
  122.                         % socket.getnameinfo(address, 0))
  123.                   self.log('Connection count: %d' % len(self.clients))
  124.    
  125.                elif s in self.clients:
  126.                   # Data from a client
  127.                   try:
  128.                      buf = s.recv(256)
  129.    
  130.                      if buf == '':
  131.                         # buffer is empty, client died!
  132.                         self.log('Lost connection from %s:%s'
  133.                               % socket.getnameinfo(s.getpeername(), 0))
  134.      
  135.                         self.clear_peer(s)
  136.                      else:
  137.                         if not self.clients[s]['auth']:
  138.                           if buf.rstrip() != self.password:
  139.                              self.send_peer(s, '- Bad password, sorry >:O')  
  140.                              self.log('Killed %s:%s: Bad password' % socket.getnameinfo(s.getpeername(), 0))
  141.                              self.clear_peer(s)
  142.                           else:
  143.                              self.clients[s]['auth'] = True
  144.                              self.send_peer(s, '+ Access granted, welcome')
  145.          
  146.                              continue
  147.      
  148.                         # Valid data!
  149.                         (host, port) = socket.getnameinfo(s.getpeername(), 0)
  150.                         self.log('<%s:%s> %s' % (host, port, buf.rstrip()))
  151.      
  152.                         if buf.rstrip() == '.close':
  153.                            self.log('Client %s:%s left me' % (host, port))
  154.                            self.send_peer(s, '+ Bye')
  155.                            self.clear_peer(s)
  156.                         else:
  157.                            self.server_stdin.write('%s\n' % buf.rstrip())
  158.                   except Exception, e:
  159.                      self.clear_peer(s)
  160.                      self.log_exception('mainloop() > clientdata', e)
  161.  
  162.                elif s == self.server.stderr or s == self.server.stdout:
  163.                   line = s.readline().rstrip()
  164.                   if line == '':
  165.                      self.do_exit()
  166.                      return True
  167.  
  168.                   self.log_server(line)
  169.  
  170.                   for i in self.clients:
  171.                      if self.clients[i]['auth']:
  172.                         if self.send_peer(i, line) == 0:
  173.                            self.log('%s:%s appears dead, removing'
  174.                                  % socket.getnameinfo(i.getpeername(), 0))
  175.    
  176.                            self.clear_peer(i)
  177.  
  178.    def do_exit(self):
  179.       self.server_socket.close()
  180.          
  181.    def send_peer(self, peer, what):
  182.       try:
  183.          return peer.send('%s\r\n' % what)
  184.       except Exception, e:
  185.          self.log_exception('send_peer()', e)
  186.    
  187.    def start_minecraft_server(self):
  188.       self.log('Starting Minecraft server...')
  189.       server_startcmd = [
  190.                "java",
  191.                "-Xmx%s" % self.java_heapmax,
  192.                "-Xms%s" % self.java_heapmin,
  193.                "-jar",
  194.                self.server_jar,
  195.                "nogui"
  196.             ]
  197.  
  198.       self.log(' > %s' % string.join(server_startcmd, " "))
  199.  
  200.       self.server = Popen(
  201.             server_startcmd,
  202.             stdout = PIPE,
  203.             stderr = PIPE,
  204.             stdin  = PIPE
  205.             )
  206.  
  207.       self.outputs = [
  208.             self.server_socket,
  209.             self.server.stderr,
  210.             self.server.stdout,
  211.             sys.stdin
  212.             ]
  213.       self.inputs  = []
  214.  
  215.       self.server_stdin = self.server.stdin
  216.  
  217.    def load_config(self):
  218.       try:
  219.          config = ConfigParser.ConfigParser()
  220.          config.readfp(StringIO(default_config))
  221.       except ConfigParser.Error, cpe:
  222.          self.log_exception('load_config()', cpe)
  223.          return False
  224.  
  225.       if os.path.isfile('mineremote.ini'):
  226.          self.log('Found configuration, loading...')
  227.  
  228.          try:
  229.             config.read('mineremote.ini')
  230.          except ConfigParser.Error, cpe:
  231.             self.log_exception('load_config()', cpe)
  232.             return False
  233.       else:
  234.          self.log('Could not find an existing configuration, creating it...')
  235.  
  236.          try:
  237.             config_file = open('mineremote.ini', 'w')
  238.             config.write(config_file)
  239.          except Exception, e:
  240.             self.log_exception('load_config()', e)
  241.             return False
  242.          finally:
  243.             config_file.close()
  244.  
  245.       try:
  246.          self.port     = config.getint('remote', 'port')
  247.          self.password = config.get('remote', 'password')
  248.  
  249.          if self.password == '':
  250.             self.password = None
  251.  
  252.          self.listenaddr = config.get('remote', 'listenaddr')
  253.  
  254.          self.server_jar = config.get('java', 'server')
  255.  
  256.          self.java_heapmax = config.get('java', 'heap_max')
  257.          self.java_heapmin = config.get('java', 'heap_min')
  258.       except Exception, e:
  259.          self.log_exception('load_config()', e)
  260.          return False
  261.  
  262.       return True
  263.  
  264.  
  265. srv = Mineremote()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement