Module pyvserv
The main pyvserv excutable. Usage: pyvserv.py [options] options: -n --host host - Set server hostname / interface. -r --dataroot droot - Set data root for server. -l --loglevel pglog - Log level (0 - 10) default = 1 -d --debug pgdebug - Debug level 0-10 -p --port port - Listen on port -v --verbose - Verbose. Show more info. -q --quiet - Quiet. Show less info. -V --version - Print Version string -h --help - Show Help. (this screen) -P --pmode - Production mode ON. (allow 2FA) Use quotes for multiple option strings.
Expand source code
#!/usr/bin/env python3
# Too many misc crappers like dyn properties
# pylint: disable=E1101
# pylint: disable=C0103
# pylint: disable=C0413
# pylint: disable=C0209
# pylint: disable=W0201
# pylint: disable=W0702 # Bare exceptions
# pylint: disable=W0602 # No global assignment
__doc__ = \
'''
Server module.
'''
import sys
import os
import getopt
import signal
import time
import subprocess
import platform
import socket
import threading
import tracemalloc
import datetime
import distro
if sys.version_info[0] < 3:
print("Python 2 is not supported as of 1/1/2020")
sys.exit(1)
try:
import fcntl
except ImportError:
fcntl = None
except:
print(sys.exc_info())
if sys.version_info[0] < 3:
import SocketServer as socketserver
else:
import socketserver
__doc__ = ''' <pre>\
The main pyvserv excutable.
Usage: pyvserv.py [options]
options:
-n --host host - Set server hostname / interface.
-r --dataroot droot - Set data root for server.
-l --loglevel pglog - Log level (0 - 10) default = 1
-d --debug pgdebug - Debug level 0-10
-p --port port - Listen on port
-v --verbose - Verbose. Show more info.
-q --quiet - Quiet. Show less info.
-V --version - Print Version string
-h --help - Show Help. (this screen)
-P --pmode - Production mode ON. (allow 2FA)
Use quotes for multiple option strings. </pre>'''
progname = os.path.split(sys.argv[0])[1]
# This repairs the path from local run to pip run.
# Remove pip version for local tests
try:
from pyvcommon import support
# Get Parent of module root
sf = os.path.dirname(support.__file__)
sf = os.path.dirname(sf)
#print("sf", sf)
sys.path.append(os.path.join(sf, "pyvcommon"))
sys.path.append(os.path.join(sf, "pyvserver"))
except:
base = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(base, '..'))
sys.path.append(os.path.join(base, '..', "pyvcommon"))
sys.path.append(os.path.join(base, '..', "pyvserver"))
from pyvcommon import support
from pyvcommon import support, pyservsup
from pyvcommon import pydata, pysyslog, comline
from pyvserver import pyvstate
from pyvserver import pyvfunc
# Create a placeholders
SHARED_MYDATA = None
gl_server = None
args = None
# ------------------------------------------------------------------------
class InvalidArg(Exception):
''' Exception for bad arguments '''
def __init__(self, message):
super().__init__(self) #InvalidArg, self)
self.message = message
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
''' Request handler. '''
def __init__(self, a1, a2, a3):
self.verbose = conf.verbose
self.pgdebug = conf.pgdebug
self.peer = a2
self.fname = ""
self.user = ""
self.preuser = ""
self.cwd = os.getcwd()
self.dir = ""
self.ekey = ""
#print("a1", a1, "a2", a2, "a3", a3)
# Throttle for multiple connectiond from one host
ttt = pyservsup.gl_throttle.throttle(a1.getpeername())
if ttt > 0:
if self.pgdebug > 2:
print("Throttle sleep", a1.getpeername())
time.sleep(ttt)
socketserver.BaseRequestHandler.__init__(self, a1, a2, a3)
def setup(self):
''' Start server '''
global SHARED_MYDATA
#print("thread", self)
#print(dir(self))
cur_thread = threading.current_thread()
#print(dir(cur_thread))
self.name = str(cur_thread._native_id) #name #getName()
#self.name = cur_thread.name #getName()
#print( "Logoff '" + usr + "'", cli)
if self.verbose:
print( "Connection from ", self.peer, "as", self.name)
self.statehandler = pyvstate.StateHandler(self)
self.statehandler.verbose = conf.verbose
self.statehandler.pglog = conf.pglog
self.statehandler.pgdebug = conf.pgdebug
self.statehandler.name = self.name
# Remeber globally, add to shared dicrtionary
ddd = (os.getpid(), self.peer[0], self.peer[1], self.request)
if conf.pgdebug > 4:
print("Adding mydata:", ddd)
SHARED_MYDATA.setdat(self.name, ddd)
self.datahandler = pydata.DataHandler(self.request)
self.datahandler.pgdebug = conf.pgdebug
self.datahandler.pglog = conf.pglog
self.datahandler.verbose = conf.verbose
self.datahandler.par = self
self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
if conf.pglog > 0:
pysyslog.syslog("Connected " + " " + str(self.client_address))
response = ["OK", "pyvserv %s ready" % pyservsup.version, self.name]
# Connected, acknowledge it
self.datahandler.putencode(response, "")
def handle_error(self, request, client_address):
''' Placeholder '''
print("pyvserv Error", request, client_address)
def handle(self):
''' Request comes in here '''
if conf.mem:
tracemalloc.start()
try:
while 1:
ret = self.datahandler.handle_one(self)
if not ret:
break
ret2 = self.statehandler.run_state(ret)
if ret2:
#response2 = ["err", "Too many tries, disconnecting."]
response2 = ["ERR", "Disconnected."]
self.datahandler.putencode(response2, self.statehandler.resp.ekey)
#time.sleep(.1)
#self.datahandler.par.request.shutdown(socket.SHUT_RDWR)
break
except:
#print( sys.exc_info())
support.put_exception("state handler")
if self.verbose:
print( "Connection closed on", self.peer)
if conf.mem:
print( "Memory trace")
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
print("[ Top 10 ]")
for stat in top_stats[:10]:
print(stat)
#if conf.pglog > 0:
# pysyslog.syslog("Disconn " + " " + str(self.client_address))
def finish(self):
''' Wind down, remove globals '''
global SHARED_MYDATA
if conf.pgdebug > 4:
ddd = SHARED_MYDATA.getdat(self.name)
print("Removing mydata:", self.name, ddd)
SHARED_MYDATA.deldat(self.name)
if self.statehandler.resp.user:
pyservsup.SHARED_LOGINS.deldat(self.statehandler.resp.user)
# ------------------------------------------------------------------------
# Override stock methods. Windows has no ForkinMixin
if not fcntl:
mixin = socketserver.ThreadingMixIn
else:
mixin = socketserver.ForkingMixIn
# Overriding it for throttle and cleanup development !! TEST !!
#mixin = socketserver.ThreadingMixIn
class ThreadedTCPServer(mixin, socketserver.TCPServer):
''' Overridden socket server '''
#def __init__(self, arg1, arg2):
# self._BaseServer__shutdown_request = True
def stop(self):
''' breakout '''
self._BaseServer__shutdown_request = True
if conf.verbose:
print( "Stop called")
#self.shutdown()
#self.server_close()
def usersig1(arg1, arg2):
''' signal comes in here, list current clients '''
global SHARED_MYDATA, gl_server
if conf.pgdebug > 1:
print("usersig", arg1)
if conf.pgdebug > 6:
print("usersig", arg1, arg2)
if conf.pglog > 2:
pysyslog.syslog("Got user signal %d" % arg1)
print("Current clients:")
print( SHARED_MYDATA.getall())
print("Current logins:")
ddd = pyservsup.SHARED_LOGINS.getall()
if ddd:
for aa in ddd.keys():
dt = datetime.datetime.fromtimestamp(ddd[aa])
print("Login:", "'" + aa + "'", "Login time:", dt)
def usersig2(arg1, arg2):
''' respond to user signaal '''
if conf.pgdebug > 1:
print("usersig2", arg1)
if conf.pgdebug > 6:
print("usersig2", arg1, arg2)
if conf.pglog > 2:
pysyslog.syslog("Got user signal2 %d" % arg1)
print("Current configuration:")
print("Full server path: ", pyservsup.globals.script_home)
print("Data root: ", pyservsup.globals.myhome)
print("Pass Dir: ", pyservsup.globals.passdir)
print("Key Dir: ", pyservsup.globals.keydir)
print("Payload Dir: ", pyservsup.globals.paydir)
print("Blockchain Dir: ", pyservsup.globals.chaindir)
print("Log dir: ", pyservsup.globals.logdir)
print("Temp dir: ", pyservsup.globals.tmpdir)
print("Lockfile: ", pyservsup.globals.lockfname)
print("IDfile: ", pyservsup.globals.idfile)
print("Current operationals:")
print("Server hostname: ", pyservsup.globals.conf.host)
print("Port listening on: ", pyservsup.globals.conf.port)
print("Debug level: ", pyservsup.globals.conf.pgdebug)
print("Verbose: ", pyservsup.globals.conf.verbose)
print("Loglevel: ", pyservsup.globals.conf.pglog)
print("Production Mode: ", pyservsup.globals.conf.pmode)
def soft_terminate(arg1 = 0, arg2 = 0):
# pylint: disable=unused-argument
''' Terminate app. Did not behave as expected ... fixed. '''
if conf.pgdebug > 1:
print(" soft_terminate")
if conf.pgdebug > 1:
print( "Dumping connection info:")
ddd = SHARED_MYDATA.getall()
for aa in ddd.keys():
print(os.getpid(), ddd[aa])
terminate() #0, 0)
# ------------------------------------------------------------------------
def terminate(arg1 = 0, arg2 = 0):
''' Terminate app. Wind down all sockets. Free locks. '''
# pylint: disable=unused-argument
global SHARED_MYDATA, gl_server
# Attempt to unhook all pending clients
#print( "Closing active clients:")
pid = os.getpid()
ddd = SHARED_MYDATA.getall()
if ddd:
for aa in ddd.keys():
if conf.pgdebug > 5:
print( "Shared data:", ddd[aa])
if pid == ddd[aa][0]:
if conf.pgdebug > 1:
print( "Closing connection:", ddd[aa])
try:
ddd[aa][3].shutdown(socket.SHUT_RDWR)
ddd[aa][3].close()
except:
print("exc on close conn", sys.exc_info())
if conf.pglog > 0:
pysyslog.syslog("Terminated Server" )
support.unlock_process(pyservsup.globals.lockfname)
if not conf.quiet:
print( "Terminated", progname)
sys.exit(2)
# ------------------------------------------------------------------------
# Execute one server cycle
# pylint: disable=too-few-public-methods
class serve_one():
''' Simplified server for testing. Kept in case we want to
temporarily revert.
'''
def __init__(self, *argx):
self.cnt = 0
self.fname = ""
self.user = ""
self.cwd = os.getcwd()
self.dir = ""
self.ekey = ""
self.argx = argx
server_thread = threading.Thread(target=self.run)
server_thread.start()
self.verbose = False
self.argx = argx
self.name = ""
self.statehandler = None
self.datahandler = None
def run(self, argx):
''' run '''
self.client, self.client_address, self.args = argx
cur_thread = threading.current_thread()
self.name = cur_thread.name #getName()
#print( "Logoff '" + usr + "'", cli)
self.verbose = conf.verbose
if self.verbose:
print("Started thread", self.name)
if self.verbose:
print( "Connection from ", self.a2, "as", self.name)
#if pgdebug > 1:
# put_debug("Connection from %s" % self.a2)
self.statehandler = pyvstate.StateHandler(self)
self.statehandler.verbose = conf.verbose
self.statehandler.pglog = conf.pglog
self.statehandler.pgdebug = conf.pgdebug
#if conf.verbose:
# print("Connected " + " " + str(self.client_address))
self.datahandler = pydata.DataHandler(self.client)
self.datahandler.pgdebug = conf.pgdebug
self.datahandler.pglog = conf.pglog
self.datahandler.verbose = conf.verbose
self.datahandler.par = self
self.client.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
if conf.pglog > 0:
pysyslog.syslog("Connected ", str(self.client_address))
response = ["OK", "pyvserv %s ready" % pyservsup.version]
# Connected, acknowledge it
self.datahandler.putencode(response, "")
try:
while 1:
ret = self.datahandler.handle_one(self)
if not ret:
break
ret2 = self.statehandler.run_state(ret)
if ret2:
#response2 = ["err", "Too many tries, disconnecting."]
response2 = ["ERR", "Disconnected."]
self.datahandler.putencode(response2, self.statehandler.resp.ekey)
break
except:
#print( sys.exc_info())
support.put_exception("state handler")
if conf.mem:
#print( "Memory trace")
#snapshot = tracemalloc.take_snapshot()
#top_stats = snapshot.statistics('lineno')
pass
if self.verbose:
print("ended thread", self.name)
def simple_server(Host, Port):
''' This was a test server, left it in for future refernence.
It was marginally faster than the stock version, also less features,
so the stock servers stayed.
'''
global args
with socket.socket() as server:
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((Host, Port))
server.listen()
while True:
client, addr = server.accept()
client.setsockopt(socket.IPPROTO_TCP,
socket.TCP_NODELAY, 1)
serve_one(client, addr, args)
# ------------------------------------------------------------------------
# Tue 02.Apr.2024 made devmode default
optarr = []
optarr.append ( ["n:", "host=", "host", "127.0.0.1",
None, "Set server hostname / interface. default=127.0.0.1"] )
optarr.append ( ["r:", "dataroot=", "droot", "pyvserver",
None, "Set data root for server. default:~/pyvserver "] )
optarr.append ( ["l:", "loglevel=", "pglog", 1,
None, "Log level. 0=none 10=noisy default=1"] )
optarr += comline.optarrlong
optarr.append ( ["m", "mem", "mem", 0,
None, "Show memory trace. (Advanced users only.)"] )
#optarr.append ( ["N", "norepl", "norepl", 0,
# None, "No replication. (for testing)"] )
optarr.append ( ["P", "pmode", "pmode", 0,
None, "Production mode ON. (allow 2FA)"] )
comline.sethead("The main pyvserv excutable.")
#comline.setprog(os.path.basename(sys.argv[0]))
comline.setprog(os.path.basename(__file__))
comline.setargs("[options]")
comline.setfoot("Use quotes for multiple option strings.")
conf = comline.ConfigLong(optarr)
#conf.printvars()
def do_keys():
''' breakout '''
try:
#keyfroot =
pyservsup.pickkey(pyservsup.globals.keydir)
except:
if conf.pgdebug > 4:
print("Could pick keys", sys.exc_info())
if conf.pgdebug > 5:
support.put_exception("pick keys")
#print("No keys generated yet. Please run pyvgenkey.py first.")
print("Notice: Generating key in", "'" + pyservsup.globals.keydir + "'")
execx = os.path.dirname(pyservsup.globals.script_home) + os.sep
execx += "../pyvtools/pyvgenkey.py"
try:
if conf.pgdebug > 4:
print("Generating keys", execx)
# Try local
if os.path.isfile(execx):
rrr = [execx, "-q", "-m", pyservsup.globals.myhome]
with subprocess.Popen(rrr):
pass
else:
# Try with full install version ... executable
execx = "pyvgenkey"
rrr = [execx, "-q", "-m", pyservsup.globals.myhome]
with subprocess.Popen(rrr):
pass
except:
if conf.pgdebug > 4:
print("Could not exec", sys.exc_info())
if conf.pgdebug > 5:
support.put_exception("generate keys")
print("Could not generate key. Keydir was:", pyservsup.globals.keydir)
print("Please try again manually with the 'pvgenkey' utility.")
print("For added security please generate more keys with 'pyvgenkeys'")
def print_stats():
''' breakout '''
if conf.verbose:
print("Serve exe path: ", pyservsup.globals.script_home)
print("Data root: ", pyservsup.globals.myhome)
print("Pass Dir: ", pyservsup.globals.passdir)
print("Key Dir: ", pyservsup.globals.keydir)
print("Payload Dir: ", pyservsup.globals.paydir)
print("Lock file: ", pyservsup.globals.lockfname)
print("ID file: ", pyservsup.globals.idfile)
#print("Passfile: ", pyservsup.globals.passfile)
def start_server():
''' breakout '''
global gl_server
try:
gl_server = ThreadedTCPServer((conf.host, conf.port), ThreadedTCPRequestHandler)
gl_server.allow_reuse_address = True
#ip, port = server.server_address
gl_server.verbose = conf.verbose
# Start a thread with the server -- that thread will then start one
# or more threads for each request
server_thread = threading.Thread(target=gl_server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.verbose = conf.verbose
server_thread.daemon = True
#server_thread.paydir = pyservsup.globals.paydir
server_thread.start()
except:
print( "Cannot start server. ", sys.exc_info())
if conf.pglog > 0:
pysyslog.syslog("Cannot start server ", sys.exc_info())
#print("Try again later.")
#terminate(None, None)
sys.exit(1)
def signon_message():
''' message for the terminal '''
if not conf.quiet:
if not pyservsup.globals.conf.pmode:
print("Warning! Devmode ON. Use -P to allow 2FA auth")
try:
strx = distro.name()
except:
strx = "Win or Unkn."
print("MainSiteID: ", pyservsup.globals.siteid)
print("Server running: ", "'"+conf.host+"'", "Port:", conf.port)
#pyver = support.list2str(sys.version_info) #[0:3], ".")
print("Running python", platform.python_version(), "on", platform.system(), strx)
def set_sigs():
''' set up signal handlers '''
# Set termination handlers, so lock will be deleted
signal.signal(signal.SIGTERM, terminate)
signal.signal(signal.SIGINT, soft_terminate)
try:
signal.signal(signal.SIGUSR1, usersig1)
signal.signal(signal.SIGUSR2, usersig2)
except:
print("User signals may not be available.")
sys.stdout = support.Unbuffered(sys.stdout)
sys.stderr = support.Unbuffered(sys.stderr)
def mainfunct():
''' Main entry point. The pip install will call this script. '''
global args
if sys.version_info[0] < 3:
print("This script was meant for python 3.x")
time.sleep(.1)
sys.exit(0)
try:
args = conf.comline(sys.argv[1:])
except getopt.GetoptError:
sys.exit(1)
except SystemExit:
sys.exit(0)
except:
print(sys.exc_info())
sys.exit(1)
#print(args)
# Print comline args
#if conf.pgdebug > 7:
# for aa in vars(conf):
# if aa != "_optarr":
# print(aa, "=", getattr(conf, aa), end = " ")
# print()
#if conf.pgdebug > 4:
# print("This script: ", os.path.realpath(__file__))
# print("Full path argv: ", os.path.abspath(sys.argv[0]))
# print("Script name: ", __file__)
# print("Exec argv: ", sys.argv[0])
# Just for testing
#pyservsup.pgdebug = conf.pgdebug
pyservsup.globals = pyservsup.Global_Vars(__file__, conf.droot)
pyservsup.globals.conf = conf
pyservsup.globals.lockfname += "_" + str(conf.host) + "_" + str(conf.port)
pyservsup.globals.softmkdir(pyservsup.globals.myhome)
# Change directory to the data dir
os.chdir(pyservsup.globals.myhome)
if conf.verbose:
print("cwd", os.getcwd())
# Create support objects
pyservsup.globals.config(pyservsup.globals.myhome, conf)
pyservsup.gl_passwd = pyservsup.Passwd()
# This is out of process, but create a 'vote' chain directory
# As testing will create it ... no harm
Vd = os.path.join(pyservsup.globals.chaindir, "vote")
pyservsup.globals.softmkdir(Vd)
print_stats()
do_keys()
set_sigs()
# Comline processed, go
support.lock_process(pyservsup.globals.lockfname)
pyvfunc.pgdebug = conf.pgdebug
pyvfunc.pglog = conf.pglog
slogfile = os.path.join(pyservsup.globals.logdir, pyservsup.logfname + ".log")
rlogfile = os.path.join(pyservsup.globals.logdir, pyservsup.repfname +".log")
pysyslog.init_loggers(
("system", slogfile), ("replic", rlogfile))
#pysyslog.syslog("Started Server")
signon_message()
pyvstate.init_state_table()
global SHARED_MYDATA
SHARED_MYDATA = pyservsup.SharedData()
pyservsup.SHARED_LOGINS = pyservsup.SharedData()
start_server()
if conf.pglog > 0:
pysyslog.syslog("Server started. Prodmode %d" % conf.pmode)
# Block
gl_server.serve_forever()
if __name__ == '__main__':
mainfunct()
# EOF
Functions
def do_keys()
-
breakout
Expand source code
def do_keys(): ''' breakout ''' try: #keyfroot = pyservsup.pickkey(pyservsup.globals.keydir) except: if conf.pgdebug > 4: print("Could pick keys", sys.exc_info()) if conf.pgdebug > 5: support.put_exception("pick keys") #print("No keys generated yet. Please run pyvgenkey.py first.") print("Notice: Generating key in", "'" + pyservsup.globals.keydir + "'") execx = os.path.dirname(pyservsup.globals.script_home) + os.sep execx += "../pyvtools/pyvgenkey.py" try: if conf.pgdebug > 4: print("Generating keys", execx) # Try local if os.path.isfile(execx): rrr = [execx, "-q", "-m", pyservsup.globals.myhome] with subprocess.Popen(rrr): pass else: # Try with full install version ... executable execx = "pyvgenkey" rrr = [execx, "-q", "-m", pyservsup.globals.myhome] with subprocess.Popen(rrr): pass except: if conf.pgdebug > 4: print("Could not exec", sys.exc_info()) if conf.pgdebug > 5: support.put_exception("generate keys") print("Could not generate key. Keydir was:", pyservsup.globals.keydir) print("Please try again manually with the 'pvgenkey' utility.") print("For added security please generate more keys with 'pyvgenkeys'")
def mainfunct()
-
Main entry point. The pip install will call this script.
Expand source code
def mainfunct(): ''' Main entry point. The pip install will call this script. ''' global args if sys.version_info[0] < 3: print("This script was meant for python 3.x") time.sleep(.1) sys.exit(0) try: args = conf.comline(sys.argv[1:]) except getopt.GetoptError: sys.exit(1) except SystemExit: sys.exit(0) except: print(sys.exc_info()) sys.exit(1) #print(args) # Print comline args #if conf.pgdebug > 7: # for aa in vars(conf): # if aa != "_optarr": # print(aa, "=", getattr(conf, aa), end = " ") # print() #if conf.pgdebug > 4: # print("This script: ", os.path.realpath(__file__)) # print("Full path argv: ", os.path.abspath(sys.argv[0])) # print("Script name: ", __file__) # print("Exec argv: ", sys.argv[0]) # Just for testing #pyservsup.pgdebug = conf.pgdebug pyservsup.globals = pyservsup.Global_Vars(__file__, conf.droot) pyservsup.globals.conf = conf pyservsup.globals.lockfname += "_" + str(conf.host) + "_" + str(conf.port) pyservsup.globals.softmkdir(pyservsup.globals.myhome) # Change directory to the data dir os.chdir(pyservsup.globals.myhome) if conf.verbose: print("cwd", os.getcwd()) # Create support objects pyservsup.globals.config(pyservsup.globals.myhome, conf) pyservsup.gl_passwd = pyservsup.Passwd() # This is out of process, but create a 'vote' chain directory # As testing will create it ... no harm Vd = os.path.join(pyservsup.globals.chaindir, "vote") pyservsup.globals.softmkdir(Vd) print_stats() do_keys() set_sigs() # Comline processed, go support.lock_process(pyservsup.globals.lockfname) pyvfunc.pgdebug = conf.pgdebug pyvfunc.pglog = conf.pglog slogfile = os.path.join(pyservsup.globals.logdir, pyservsup.logfname + ".log") rlogfile = os.path.join(pyservsup.globals.logdir, pyservsup.repfname +".log") pysyslog.init_loggers( ("system", slogfile), ("replic", rlogfile)) #pysyslog.syslog("Started Server") signon_message() pyvstate.init_state_table() global SHARED_MYDATA SHARED_MYDATA = pyservsup.SharedData() pyservsup.SHARED_LOGINS = pyservsup.SharedData() start_server() if conf.pglog > 0: pysyslog.syslog("Server started. Prodmode %d" % conf.pmode) # Block gl_server.serve_forever()
def print_stats()
-
breakout
Expand source code
def print_stats(): ''' breakout ''' if conf.verbose: print("Serve exe path: ", pyservsup.globals.script_home) print("Data root: ", pyservsup.globals.myhome) print("Pass Dir: ", pyservsup.globals.passdir) print("Key Dir: ", pyservsup.globals.keydir) print("Payload Dir: ", pyservsup.globals.paydir) print("Lock file: ", pyservsup.globals.lockfname) print("ID file: ", pyservsup.globals.idfile) #print("Passfile: ", pyservsup.globals.passfile)
def set_sigs()
-
set up signal handlers
Expand source code
def set_sigs(): ''' set up signal handlers ''' # Set termination handlers, so lock will be deleted signal.signal(signal.SIGTERM, terminate) signal.signal(signal.SIGINT, soft_terminate) try: signal.signal(signal.SIGUSR1, usersig1) signal.signal(signal.SIGUSR2, usersig2) except: print("User signals may not be available.") sys.stdout = support.Unbuffered(sys.stdout) sys.stderr = support.Unbuffered(sys.stderr)
def signon_message()
-
message for the terminal
Expand source code
def signon_message(): ''' message for the terminal ''' if not conf.quiet: if not pyservsup.globals.conf.pmode: print("Warning! Devmode ON. Use -P to allow 2FA auth") try: strx = distro.name() except: strx = "Win or Unkn." print("MainSiteID: ", pyservsup.globals.siteid) print("Server running: ", "'"+conf.host+"'", "Port:", conf.port) #pyver = support.list2str(sys.version_info) #[0:3], ".") print("Running python", platform.python_version(), "on", platform.system(), strx)
def simple_server(Host, Port)
-
This was a test server, left it in for future refernence. It was marginally faster than the stock version, also less features, so the stock servers stayed.
Expand source code
def simple_server(Host, Port): ''' This was a test server, left it in for future refernence. It was marginally faster than the stock version, also less features, so the stock servers stayed. ''' global args with socket.socket() as server: server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((Host, Port)) server.listen() while True: client, addr = server.accept() client.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) serve_one(client, addr, args)
def soft_terminate(arg1=0, arg2=0)
-
Terminate app. Did not behave as expected … fixed.
Expand source code
def soft_terminate(arg1 = 0, arg2 = 0): # pylint: disable=unused-argument ''' Terminate app. Did not behave as expected ... fixed. ''' if conf.pgdebug > 1: print(" soft_terminate") if conf.pgdebug > 1: print( "Dumping connection info:") ddd = SHARED_MYDATA.getall() for aa in ddd.keys(): print(os.getpid(), ddd[aa]) terminate() #0, 0)
def start_server()
-
breakout
Expand source code
def start_server(): ''' breakout ''' global gl_server try: gl_server = ThreadedTCPServer((conf.host, conf.port), ThreadedTCPRequestHandler) gl_server.allow_reuse_address = True #ip, port = server.server_address gl_server.verbose = conf.verbose # Start a thread with the server -- that thread will then start one # or more threads for each request server_thread = threading.Thread(target=gl_server.serve_forever) # Exit the server thread when the main thread terminates server_thread.verbose = conf.verbose server_thread.daemon = True #server_thread.paydir = pyservsup.globals.paydir server_thread.start() except: print( "Cannot start server. ", sys.exc_info()) if conf.pglog > 0: pysyslog.syslog("Cannot start server ", sys.exc_info()) #print("Try again later.") #terminate(None, None) sys.exit(1)
def terminate(arg1=0, arg2=0)
-
Terminate app. Wind down all sockets. Free locks.
Expand source code
def terminate(arg1 = 0, arg2 = 0): ''' Terminate app. Wind down all sockets. Free locks. ''' # pylint: disable=unused-argument global SHARED_MYDATA, gl_server # Attempt to unhook all pending clients #print( "Closing active clients:") pid = os.getpid() ddd = SHARED_MYDATA.getall() if ddd: for aa in ddd.keys(): if conf.pgdebug > 5: print( "Shared data:", ddd[aa]) if pid == ddd[aa][0]: if conf.pgdebug > 1: print( "Closing connection:", ddd[aa]) try: ddd[aa][3].shutdown(socket.SHUT_RDWR) ddd[aa][3].close() except: print("exc on close conn", sys.exc_info()) if conf.pglog > 0: pysyslog.syslog("Terminated Server" ) support.unlock_process(pyservsup.globals.lockfname) if not conf.quiet: print( "Terminated", progname) sys.exit(2)
def usersig1(arg1, arg2)
-
signal comes in here, list current clients
Expand source code
def usersig1(arg1, arg2): ''' signal comes in here, list current clients ''' global SHARED_MYDATA, gl_server if conf.pgdebug > 1: print("usersig", arg1) if conf.pgdebug > 6: print("usersig", arg1, arg2) if conf.pglog > 2: pysyslog.syslog("Got user signal %d" % arg1) print("Current clients:") print( SHARED_MYDATA.getall()) print("Current logins:") ddd = pyservsup.SHARED_LOGINS.getall() if ddd: for aa in ddd.keys(): dt = datetime.datetime.fromtimestamp(ddd[aa]) print("Login:", "'" + aa + "'", "Login time:", dt)
def usersig2(arg1, arg2)
-
respond to user signaal
Expand source code
def usersig2(arg1, arg2): ''' respond to user signaal ''' if conf.pgdebug > 1: print("usersig2", arg1) if conf.pgdebug > 6: print("usersig2", arg1, arg2) if conf.pglog > 2: pysyslog.syslog("Got user signal2 %d" % arg1) print("Current configuration:") print("Full server path: ", pyservsup.globals.script_home) print("Data root: ", pyservsup.globals.myhome) print("Pass Dir: ", pyservsup.globals.passdir) print("Key Dir: ", pyservsup.globals.keydir) print("Payload Dir: ", pyservsup.globals.paydir) print("Blockchain Dir: ", pyservsup.globals.chaindir) print("Log dir: ", pyservsup.globals.logdir) print("Temp dir: ", pyservsup.globals.tmpdir) print("Lockfile: ", pyservsup.globals.lockfname) print("IDfile: ", pyservsup.globals.idfile) print("Current operationals:") print("Server hostname: ", pyservsup.globals.conf.host) print("Port listening on: ", pyservsup.globals.conf.port) print("Debug level: ", pyservsup.globals.conf.pgdebug) print("Verbose: ", pyservsup.globals.conf.verbose) print("Loglevel: ", pyservsup.globals.conf.pglog) print("Production Mode: ", pyservsup.globals.conf.pmode)
Classes
class InvalidArg (message)
-
Exception for bad arguments
Expand source code
class InvalidArg(Exception): ''' Exception for bad arguments ''' def __init__(self, message): super().__init__(self) #InvalidArg, self) self.message = message
Ancestors
- builtins.Exception
- builtins.BaseException
class ThreadedTCPRequestHandler (a1, a2, a3)
-
Request handler.
Expand source code
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): ''' Request handler. ''' def __init__(self, a1, a2, a3): self.verbose = conf.verbose self.pgdebug = conf.pgdebug self.peer = a2 self.fname = "" self.user = "" self.preuser = "" self.cwd = os.getcwd() self.dir = "" self.ekey = "" #print("a1", a1, "a2", a2, "a3", a3) # Throttle for multiple connectiond from one host ttt = pyservsup.gl_throttle.throttle(a1.getpeername()) if ttt > 0: if self.pgdebug > 2: print("Throttle sleep", a1.getpeername()) time.sleep(ttt) socketserver.BaseRequestHandler.__init__(self, a1, a2, a3) def setup(self): ''' Start server ''' global SHARED_MYDATA #print("thread", self) #print(dir(self)) cur_thread = threading.current_thread() #print(dir(cur_thread)) self.name = str(cur_thread._native_id) #name #getName() #self.name = cur_thread.name #getName() #print( "Logoff '" + usr + "'", cli) if self.verbose: print( "Connection from ", self.peer, "as", self.name) self.statehandler = pyvstate.StateHandler(self) self.statehandler.verbose = conf.verbose self.statehandler.pglog = conf.pglog self.statehandler.pgdebug = conf.pgdebug self.statehandler.name = self.name # Remeber globally, add to shared dicrtionary ddd = (os.getpid(), self.peer[0], self.peer[1], self.request) if conf.pgdebug > 4: print("Adding mydata:", ddd) SHARED_MYDATA.setdat(self.name, ddd) self.datahandler = pydata.DataHandler(self.request) self.datahandler.pgdebug = conf.pgdebug self.datahandler.pglog = conf.pglog self.datahandler.verbose = conf.verbose self.datahandler.par = self self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) if conf.pglog > 0: pysyslog.syslog("Connected " + " " + str(self.client_address)) response = ["OK", "pyvserv %s ready" % pyservsup.version, self.name] # Connected, acknowledge it self.datahandler.putencode(response, "") def handle_error(self, request, client_address): ''' Placeholder ''' print("pyvserv Error", request, client_address) def handle(self): ''' Request comes in here ''' if conf.mem: tracemalloc.start() try: while 1: ret = self.datahandler.handle_one(self) if not ret: break ret2 = self.statehandler.run_state(ret) if ret2: #response2 = ["err", "Too many tries, disconnecting."] response2 = ["ERR", "Disconnected."] self.datahandler.putencode(response2, self.statehandler.resp.ekey) #time.sleep(.1) #self.datahandler.par.request.shutdown(socket.SHUT_RDWR) break except: #print( sys.exc_info()) support.put_exception("state handler") if self.verbose: print( "Connection closed on", self.peer) if conf.mem: print( "Memory trace") snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') print("[ Top 10 ]") for stat in top_stats[:10]: print(stat) #if conf.pglog > 0: # pysyslog.syslog("Disconn " + " " + str(self.client_address)) def finish(self): ''' Wind down, remove globals ''' global SHARED_MYDATA if conf.pgdebug > 4: ddd = SHARED_MYDATA.getdat(self.name) print("Removing mydata:", self.name, ddd) SHARED_MYDATA.deldat(self.name) if self.statehandler.resp.user: pyservsup.SHARED_LOGINS.deldat(self.statehandler.resp.user)
Ancestors
- socketserver.BaseRequestHandler
Methods
def finish(self)
-
Wind down, remove globals
Expand source code
def finish(self): ''' Wind down, remove globals ''' global SHARED_MYDATA if conf.pgdebug > 4: ddd = SHARED_MYDATA.getdat(self.name) print("Removing mydata:", self.name, ddd) SHARED_MYDATA.deldat(self.name) if self.statehandler.resp.user: pyservsup.SHARED_LOGINS.deldat(self.statehandler.resp.user)
def handle(self)
-
Request comes in here
Expand source code
def handle(self): ''' Request comes in here ''' if conf.mem: tracemalloc.start() try: while 1: ret = self.datahandler.handle_one(self) if not ret: break ret2 = self.statehandler.run_state(ret) if ret2: #response2 = ["err", "Too many tries, disconnecting."] response2 = ["ERR", "Disconnected."] self.datahandler.putencode(response2, self.statehandler.resp.ekey) #time.sleep(.1) #self.datahandler.par.request.shutdown(socket.SHUT_RDWR) break except: #print( sys.exc_info()) support.put_exception("state handler") if self.verbose: print( "Connection closed on", self.peer) if conf.mem: print( "Memory trace") snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') print("[ Top 10 ]") for stat in top_stats[:10]: print(stat) #if conf.pglog > 0: # pysyslog.syslog("Disconn " + " " + str(self.client_address))
def handle_error(self, request, client_address)
-
Placeholder
Expand source code
def handle_error(self, request, client_address): ''' Placeholder ''' print("pyvserv Error", request, client_address)
def setup(self)
-
Start server
Expand source code
def setup(self): ''' Start server ''' global SHARED_MYDATA #print("thread", self) #print(dir(self)) cur_thread = threading.current_thread() #print(dir(cur_thread)) self.name = str(cur_thread._native_id) #name #getName() #self.name = cur_thread.name #getName() #print( "Logoff '" + usr + "'", cli) if self.verbose: print( "Connection from ", self.peer, "as", self.name) self.statehandler = pyvstate.StateHandler(self) self.statehandler.verbose = conf.verbose self.statehandler.pglog = conf.pglog self.statehandler.pgdebug = conf.pgdebug self.statehandler.name = self.name # Remeber globally, add to shared dicrtionary ddd = (os.getpid(), self.peer[0], self.peer[1], self.request) if conf.pgdebug > 4: print("Adding mydata:", ddd) SHARED_MYDATA.setdat(self.name, ddd) self.datahandler = pydata.DataHandler(self.request) self.datahandler.pgdebug = conf.pgdebug self.datahandler.pglog = conf.pglog self.datahandler.verbose = conf.verbose self.datahandler.par = self self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) if conf.pglog > 0: pysyslog.syslog("Connected " + " " + str(self.client_address)) response = ["OK", "pyvserv %s ready" % pyservsup.version, self.name] # Connected, acknowledge it self.datahandler.putencode(response, "")
class ThreadedTCPServer (server_address, RequestHandlerClass, bind_and_activate=True)
-
Overridden socket server
Constructor. May be extended, do not override.
Expand source code
class ThreadedTCPServer(mixin, socketserver.TCPServer): ''' Overridden socket server ''' #def __init__(self, arg1, arg2): # self._BaseServer__shutdown_request = True def stop(self): ''' breakout ''' self._BaseServer__shutdown_request = True if conf.verbose: print( "Stop called") #self.shutdown() #self.server_close()
Ancestors
- socketserver.ForkingMixIn
- socketserver.TCPServer
- socketserver.BaseServer
Methods
def stop(self)
-
breakout
Expand source code
def stop(self): ''' breakout ''' self._BaseServer__shutdown_request = True if conf.verbose: print( "Stop called") #self.shutdown() #self.server_close()
class serve_one (*argx)
-
Simplified server for testing. Kept in case we want to temporarily revert.
Expand source code
class serve_one(): ''' Simplified server for testing. Kept in case we want to temporarily revert. ''' def __init__(self, *argx): self.cnt = 0 self.fname = "" self.user = "" self.cwd = os.getcwd() self.dir = "" self.ekey = "" self.argx = argx server_thread = threading.Thread(target=self.run) server_thread.start() self.verbose = False self.argx = argx self.name = "" self.statehandler = None self.datahandler = None def run(self, argx): ''' run ''' self.client, self.client_address, self.args = argx cur_thread = threading.current_thread() self.name = cur_thread.name #getName() #print( "Logoff '" + usr + "'", cli) self.verbose = conf.verbose if self.verbose: print("Started thread", self.name) if self.verbose: print( "Connection from ", self.a2, "as", self.name) #if pgdebug > 1: # put_debug("Connection from %s" % self.a2) self.statehandler = pyvstate.StateHandler(self) self.statehandler.verbose = conf.verbose self.statehandler.pglog = conf.pglog self.statehandler.pgdebug = conf.pgdebug #if conf.verbose: # print("Connected " + " " + str(self.client_address)) self.datahandler = pydata.DataHandler(self.client) self.datahandler.pgdebug = conf.pgdebug self.datahandler.pglog = conf.pglog self.datahandler.verbose = conf.verbose self.datahandler.par = self self.client.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) if conf.pglog > 0: pysyslog.syslog("Connected ", str(self.client_address)) response = ["OK", "pyvserv %s ready" % pyservsup.version] # Connected, acknowledge it self.datahandler.putencode(response, "") try: while 1: ret = self.datahandler.handle_one(self) if not ret: break ret2 = self.statehandler.run_state(ret) if ret2: #response2 = ["err", "Too many tries, disconnecting."] response2 = ["ERR", "Disconnected."] self.datahandler.putencode(response2, self.statehandler.resp.ekey) break except: #print( sys.exc_info()) support.put_exception("state handler") if conf.mem: #print( "Memory trace") #snapshot = tracemalloc.take_snapshot() #top_stats = snapshot.statistics('lineno') pass if self.verbose: print("ended thread", self.name)
Methods
def run(self, argx)
-
run
Expand source code
def run(self, argx): ''' run ''' self.client, self.client_address, self.args = argx cur_thread = threading.current_thread() self.name = cur_thread.name #getName() #print( "Logoff '" + usr + "'", cli) self.verbose = conf.verbose if self.verbose: print("Started thread", self.name) if self.verbose: print( "Connection from ", self.a2, "as", self.name) #if pgdebug > 1: # put_debug("Connection from %s" % self.a2) self.statehandler = pyvstate.StateHandler(self) self.statehandler.verbose = conf.verbose self.statehandler.pglog = conf.pglog self.statehandler.pgdebug = conf.pgdebug #if conf.verbose: # print("Connected " + " " + str(self.client_address)) self.datahandler = pydata.DataHandler(self.client) self.datahandler.pgdebug = conf.pgdebug self.datahandler.pglog = conf.pglog self.datahandler.verbose = conf.verbose self.datahandler.par = self self.client.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) if conf.pglog > 0: pysyslog.syslog("Connected ", str(self.client_address)) response = ["OK", "pyvserv %s ready" % pyservsup.version] # Connected, acknowledge it self.datahandler.putencode(response, "") try: while 1: ret = self.datahandler.handle_one(self) if not ret: break ret2 = self.statehandler.run_state(ret) if ret2: #response2 = ["err", "Too many tries, disconnecting."] response2 = ["ERR", "Disconnected."] self.datahandler.putencode(response2, self.statehandler.resp.ekey) break except: #print( sys.exc_info()) support.put_exception("state handler") if conf.mem: #print( "Memory trace") #snapshot = tracemalloc.take_snapshot() #top_stats = snapshot.statistics('lineno') pass if self.verbose: print("ended thread", self.name)