Advertisement
Guest User

Untitled

a guest
Aug 12th, 2010
267
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.40 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 as 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 as 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 as 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.                   self.clients[client] = dict(
  108.                            {
  109.                               'socket': client,
  110.                               'auth': False,
  111.                               'connected': int(time.time())
  112.                            }
  113.                         )
  114.    
  115.                   self.log('Got a new connection from %s:%s'
  116.                         % socket.getnameinfo(address, 0))
  117.                   self.log('Connection count: %d' % len(self.clients))
  118.    
  119.                elif s in self.clients:
  120.                   # Data from a client
  121.                   try:
  122.                      buf = s.recv(256)
  123.    
  124.                      if buf == '':
  125.                         # buffer is empty, client died!
  126.                         self.log('Lost connection from %s:%s'
  127.                               % socket.getnameinfo(s.getpeername(), 0))
  128.      
  129.                         self.clear_peer(s)
  130.                      else:
  131.                         if not self.clients[s]['auth']:
  132.                            if self.password:
  133.                               if buf.rstrip() != self.password:
  134.                                  self.send_peer(s, '- Bad password, sorry >:O')  
  135.                                  self.log('Killed %s:%s: Bad password' % socket.getnameinfo(s.getpeername(), 0))
  136.                                  self.clear_peer(s)
  137.                               else:
  138.                                  self.clients[s]['auth'] = True
  139.                                  self.send_peer(s, '+ Access granted, welcome')
  140.          
  141.                                  continue
  142.                            else:
  143.                               self.clients[s]['auth'] = True
  144.      
  145.                         # Valid data!
  146.                         (host, port) = socket.getnameinfo(s.getpeername(), 0)
  147.                         self.log('<%s:%s> %s' % (host, port, buf.rstrip()))
  148.      
  149.                         if buf.rstrip() == '.close':
  150.                            self.log('Client %s:%s left me' % (host, port))
  151.                            self.send_peer(s, '+ Bye')
  152.                            self.clear_peer(s)
  153.                         else:
  154.                            self.server_stdin.write('%s\n' % buf.rstrip())
  155.                   except Exception as e:
  156.                      self.clear_peer(s)
  157.                      self.log_exception('mainloop() > clientdata', e)
  158.  
  159.                elif s == self.server.stderr or s == self.server.stdout:
  160.                   line = s.readline().rstrip()
  161.                   if line == '':
  162.                      self.do_exit()
  163.                      return True
  164.  
  165.                   self.log_server(line)
  166.  
  167.                   for i in self.clients:
  168.                      if self.clients[i]['auth']:
  169.                         if self.send_peer(i, line) == 0:
  170.                            self.log('%s:%s appears dead, removing'
  171.                                  % socket.getnameinfo(i.getpeername(), 0))
  172.    
  173.                            self.clear_peer(i)
  174.  
  175.    def do_exit(self):
  176.       self.server_socket.close()
  177.          
  178.    def send_peer(self, peer, what):
  179.       try:
  180.          return peer.send('%s\r\n' % what)
  181.       except e:
  182.          log_exception('send_peer()', e)
  183.    
  184.    def start_minecraft_server(self):
  185.       self.log('Starting Minecraft server...')
  186.       server_startcmd = [
  187.                "java",
  188.                "-Xmx%s" % self.java_heapmax,
  189.                "-Xms%s" % self.java_heapmin,
  190.                "-jar",
  191.                self.server_jar,
  192.                "nogui"
  193.             ]
  194.  
  195.       self.log(' > %s' % string.join(server_startcmd, " "))
  196.  
  197.       self.server = Popen(
  198.             server_startcmd,
  199.             stdout = PIPE,
  200.             stderr = PIPE,
  201.             stdin  = PIPE
  202.             )
  203.  
  204.       self.outputs = [
  205.             self.server_socket,
  206.             self.server.stderr,
  207.             self.server.stdout,
  208.             sys.stdin
  209.             ]
  210.       self.inputs  = []
  211.  
  212.       self.server_stdin = self.server.stdin
  213.  
  214.    def load_config(self):
  215.       try:
  216.          config = ConfigParser.ConfigParser()
  217.          config.readfp(StringIO(default_config))
  218.       except ConfigParser.Error as cpe:
  219.          self.log_exception('load_config()', cpe)
  220.          return False
  221.  
  222.       if os.path.isfile('mineremote.ini'):
  223.          self.log('Found configuration, loading...')
  224.  
  225.          try:
  226.             config.read('mineremote.ini')
  227.          except ConfigParser.Error as cpe:
  228.             self.log_exception('load_config()', cpe)
  229.             return False
  230.       else:
  231.          self.log('Could not find an existing configuration, creating it...')
  232.  
  233.          try:
  234.             config_file = open('mineremote.ini', 'w')
  235.             config.write(config_file)
  236.          except Exception as e:
  237.             self.log_exception('load_config()', e)
  238.             return False
  239.          finally:
  240.             config_file.close()
  241.  
  242.       try:
  243.          self.port     = config.getint('remote', 'port')
  244.          self.password = config.get('remote', 'password')
  245.  
  246.          if self.password == '':
  247.             self.password = None
  248.  
  249.          self.listenaddr = config.get('remote', 'listenaddr')
  250.  
  251.          self.server_jar = config.get('java', 'server')
  252.  
  253.          self.java_heapmax = config.get('java', 'heap_max')
  254.          self.java_heapmin = config.get('java', 'heap_min')
  255.       except Exception as e:
  256.          self.log_exception('load_config()', e)
  257.          return False
  258.  
  259.       return True
  260.  
  261.  
  262. srv = Mineremote()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement