def _create_local_socket(self, init=0):
		"""Create local Unix-socket to listen commands instead of signals. If
		I{init} is set then close old socket"""

		if init and self.__local_sock:
			try:
				os.unlink(self.__local_sock.getsockname())
				self.__local_sock.shutdown(socket.SHUT_RDWR)
				logging.info('old local socket closed')
			except Exception as e:
				logging.warn('old local socket is already closed')

		try:
			os.unlink(self._config['server']['sock'])
		except:
			pass

		try:
			self.__local_sock = \
				socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
			# Non-blocking mode
			self.__local_sock.settimeout(0.0)
			self.__local_sock.bind(self._config['server']['sock'])
			self.__local_sock.listen(1)		# Max num of queued connections
		except Exception as e:
			logging.critical('cannot create local socket')
			logging.error(e)
			raise e

		logging.info('local socket created and binded on %s' % \
			self.__local_sock.getsockname())
	def stop(self):
		logging.info('stopping daemon')
		# Get the pid from the pidfile
		try:
			pf = open(self.pidfile, 'r')
			pid = int(pf.read().strip())
			pf.close()
		except IOError:
			pid = None

		#print (sys.stderr, sys.stdout)
		if not pid:
			logging.warn('daemon is already stopped')
			sys.stderr.write('daemon is already stopped\n')
			return

		# Try killing the daemon process
		try:
			while 1:
				os.kill(pid, signal.SIGTERM)
				sleep(0.1)
		except OSError as err:
			# PID file is present, but no process!
			err = '%s' %err
			if err.find('No such process') >0:
				if os.path.isfile(self.pidfile):
					os.remove(self.pidfile)
			else:
				sys.stderr.write(err)
				sys.exit(1)
def clean_on_exit(fp_sock):
	"""Method executed on process exit"""

	logging.info('clean up on process exit')
	try:	os.remove(fp_sock)
	except:	pass
	logging.info('shutdown logging system')
	logging.close()
	def log_message(self, format, *args):
		"""Rewrite default log handler. Log client IP address/port and verbose
		response of HTTP response code"""

		format = '%s:%s ' % self.client_address + format
		if args and len(args) >2 and args[1].isdigit() and \
				self.responses.get(int(args[1])):
			format += ' %s'
			args += (self.responses.get(int(args[1]))[0],)
		logging.info(format % args)
	def handle_sigusr2(self, signum, frame):
		"""Handle signal SIGUSR2 to reload aliases configuration"""

		logging.info('reload aliases configuration (by signal)')
		# Catch received signal in the I{main} method
		self.__by_signal_do = 1

		aliases = get_aliases(self._config['get']['aliases_file'])
		try:
			check_aliases(self._config['get']['base_dir'], aliases)
			self._aliases = aliases.copy()
			logging.info('aliases configuration reloaded')
		except Exception as e:
			logging.warn('aliases configuration error')
		del aliases
	def daemonize(self, parent1=None, parent2=None):
		"""
		Do the UNIX double-fork magic, see Stevens' I{"Advanced Programming in
		the UNIX Environment"} for details (B{ISBN 0201563177}) on
		U{http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16}.
		I{parent1}, I{parent2} - continue parent process with this functions.
		"""

		# Check for a pidfile to see if the daemon already runned
		if os.path.isfile(self.pidfile):
			msg_stdout('PID-file %s found! Remove it manually' % self.pidfile)
			return

		#logging.info('fork #1 process')
		try:
			pid = os.fork()
			if pid >0:
				if parent1:
					parent1(pid)
				# Exit first parent
				sys.exit()
		except OSError as e:
			logging.error('fork #1 failed: %d (%s)' % (e.errno, e.strerror))
			sys.exit(1)

		# Decouple from parent environment
		os.setsid()
		os.umask(0)

		# Do second fork
		#logging.info('fork #2 process')
		try:
			pid = os.fork()
			if pid >0:
				if parent2:
					parent2(pid)
				# Exit from second parent
				sys.exit()
		except OSError as e:
			logging.error('fork #2 failed: %d (%s)' % (e.errno, e.strerror))
			sys.exit(1)

		atexit.register(self.delpid)
		pid = str(os.getpid())
		open(self.pidfile,'w+').write('%s\n' % pid)
		logging.info('write PID (%s) to %s' % (pid, self.pidfile))

		return 1
	def handle_sigusr1(self, signum, frame):
		"""Handle signal SIGUSR1 to reload server configuration"""

		logging.info('reload server configuration (by signal)')
		# Catch exception in the I{main} method caused by received signal
		self.__by_signal_do = 1
		config = get_conf(CFG_PATH)

		# PID file cannot be changed
		config['server']['pid'] = self._config['server']['pid']

		# Log file path changed
		if self._config['server']['log'] != config['server']['log']:
			logging.close(0)
			logging.init(0, filename=config['server']['log'])

		# Local socket path changed
		init_loc = (config['server']['sock'] != self._config['server']['sock'])

		# SSL option changed and/or server ip/port, we need to
		# shutdown current socket and open new one
		init_srv = (config['ssl'] != self._config['ssl'] \
			or config['server']['port'] != self._config['server']['port'] \
			or config['server']['ip'] != self._config['server']['ip'])

		self._config = config.copy()

		if init_srv:
			try:
				self.socket.shutdown(socket.SHUT_RDWR)
				self._create_bind_activate(1)
			except Exception as e:
				# @todo: fix: if cannot bind new socket, do not reload config
				self.__by_signal_do = 0
				logging.error(e)

		if init_loc:
			try:
				self._create_local_socket(1)
			except Exception as e:
				pass

		self.socket.settimeout(config['server']['timeout'])
		# Non-blocking mode
		self.__local_sock.settimeout(0.0)
		logging.info('server configuration reloaded')
		del config
	def _create_bind_activate(self, init=0):
		"""Create socket, bind and activate server"""

		try:
			self._create_new_socket(init)
		except Exception as e:
			logging.critical('cannot create new socket')
			logging.error(e)
			raise e

		try:
			self.server_bind()
			self.server_activate()
		except Exception as e:
			logging.critical('cannot bind/activate server: %s' %e)
			raise e
		logging.info('server binded and activated on %s:%s' % \
			self.socket.getsockname())
	def get_request(self):
		sock, addr = ThreadingTCPServer.get_request(self)
		logging.info('%s:%s incoming request' % addr)
		return sock, addr
	def main(self):
		"""Start main loop. From that moment the process will loop forever
		in this method"""

		logging.info('*' *50)
		logging.info('python %s' % sys.version.replace('\n', ''))
		logging.info('server started on %s:%s' % self.socket.getsockname())
		logging.info('SSL enabled' if self.cfg_ssl_enabled() else \
			'SSL disabled')
		logging.info('clients certificate ' + \
			('used' if self.cfg_certs_used() else 'not used'))
		logging.info(
			'local socket activated on %s' % self.__local_sock.getsockname())
		logging.info('pid (%d) written to %s' % (os.getpid(), self.pidfile))

		while 1:
			try:
				self.handle_request()
				# If we received shutdown request from local socket
				is_quit = self.handle_local_request()
				if is_quit:
					logging.info('stopping daemon')
					break
			except Exception as e:
				if self.__by_signal_do:
					self.__by_signal_do = 0
					continue
				from traceback import format_exception
				i = sys.exc_info()
				logging.error('\n'.join(format_exception(i[0], i[1], i[2])))
				del i
				break
	def handle_local_request(self):
		"""Accept local socket connections"""

		c = None
		is_quit = 0
		try:
			# Are we have connection try?
			r, w, e = select.select([self.__local_sock.fileno()], [], [],
				self._config['server']['wait'])
			if not r:
				return
			c, addr, = self.__local_sock.accept()
			logging.info('local connection accepted')

			# Check if socket is ready for reading
			msg = b''
			r, w, e = select.select([c.fileno()], [], [], 0)
			if r:
				msg = c.recv(32, socket.MSG_DONTWAIT)
			else:
				logging.warn('socket not ready for reading')
				raise socket.error(100, 'socket not ready for reading')

			reply = b'unknown command'
			if msg == b'config':
				logging.info('request server configuration')
				reply = cpickle_dumps(self._config)
			elif msg == b'status':
				logging.info('request server status')
				reply = b'started'
			elif msg == b'shutdown':
				logging.info('request server shutdown')
				is_quit = 1
				reply = b'stopped'
			elif not msg:
				logging.info('no request')
			else:
				logging.info('unknown request')

			# Check if socket is ready for writing
			r, w, e = select.select([], [c.fileno()], [], 0)
			if w:
				c.send(reply, socket.MSG_DONTWAIT)
			else:
				logging.warn('socket not ready for writing')
				raise socket.error(101, 'socket not ready for writing')

		except Exception as e:
			logging.error(e)

		if c and not c._closed:
			c.close()
			logging.info('local connection closed')

		return is_quit
	def _create_new_socket(self, init):
		"""Create new socket. I{init} >0 if need to replace internal server
		address used in the base class to create and bind socket"""

		if init:
			self.server_address = \
				(self._config['server']['ip'], self._config['server']['port'],)
			self.socket = socket.socket(self.address_family, self.socket_type)
			self.socket.settimeout(self._config['server']['timeout'])
			logging.info('network socket created')

		if self._config['ssl'].get('enable', 0) ==0:
			logging.info('SSL disabled')
			return

		logging.info('SSL enabled')
		try:
			logging.info('socket replaced by SSLSocket')
			import ssl
			if self._config['ssl'].get('verify_client', 0) ==0:
				logging.info('clients certificates not used')
				self.socket = ssl.SSLSocket(None,
					self._config['ssl']['pkey_file'],
					self._config['ssl']['cert_file'], True,
					ssl.CERT_NONE, ssl.PROTOCOL_SSLv3)
			else:
				logging.info('clients certificate required')
				self.socket = ssl.SSLSocket(None,
					self._config['ssl']['pkey_file'],
					self._config['ssl']['cert_file'], True,
					ssl.CERT_REQUIRED, ssl.PROTOCOL_SSLv3,
					self._config['ssl']['verify_loc'])
			self.socket.settimeout(self._config['server']['timeout'])
		except Exception as e:
			logging.error(e)
			raise RuntimeError('SSL error')
		server = AsyncHTTPServer(config, SFSHTTPHandler)
		msg_stdout('Network socket created')
		server._aliases = aliases.copy()

		# Catch SIGUSR1 signal to reload server configuration
		signal.signal(signal.SIGUSR1, server.handle_sigusr1)
		# Catch SIGUSR2 signal to reload aliases configuration
		signal.signal(signal.SIGUSR2, server.handle_sigusr2)
		msg_stdout('Signal handlers registered')

		if server.activate():
			msg_stdout('Server activated', flush_buf=1)
			# Send message to local socket in the first parent process
			r = server.daemonize()
			if r:
				logging.info('forked as daemon process')
				# Close logging, init new to file
				logging.close(0)
				logging.init(0, filename=config['server']['log'])
				# Delete local socket on FS when process exit
				atexit.register(clean_on_exit, config['server']['sock'])
				# Start main loop
				server.main()
			else:
				msg_stdout('Error: can\'t daemonize', 2)

	elif sys.argv[1].lower() == 'stop':
		msg_sock(config['server'], 'shutdown', 0)

	elif sys.argv[1].lower() == 'reload':
		signal_to_daemon(config['server']['pid'], signal.SIGUSR1)