Server Remastered
This commit is contained in:
parent
bf8505554f
commit
eb05c89d47
@ -25,14 +25,15 @@ import subprocess
|
|||||||
import configparser
|
import configparser
|
||||||
import time
|
import time
|
||||||
|
|
||||||
outThreads = {}
|
|
||||||
inThreads = {}
|
|
||||||
connections = {}
|
connections = {}
|
||||||
threadId = 0
|
connectionsId = 0
|
||||||
threadsLock = threading.Lock()
|
|
||||||
fileLock = threading.Lock()
|
|
||||||
connectionsLock = threading.Lock()
|
connectionsLock = threading.Lock()
|
||||||
|
|
||||||
|
threadCount = 0
|
||||||
|
threadCountLock = threading.Lock()
|
||||||
|
|
||||||
|
fileLock = threading.Lock()
|
||||||
|
|
||||||
serverAddr = ("127.0.0.1",61920)
|
serverAddr = ("127.0.0.1",61920)
|
||||||
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
@ -43,6 +44,18 @@ maxClientsPerIP = 3 # How many clients can be connected at maximum, per IP?
|
|||||||
maxAccumulatedData = 50*1000*1000 # How much data can be in an outbound thread's queue at maximum before the connection is closed? The maximum amount of queue data is maxAccumulatedData * maxClients bytes.
|
maxAccumulatedData = 50*1000*1000 # How much data can be in an outbound thread's queue at maximum before the connection is closed? The maximum amount of queue data is maxAccumulatedData * maxClients bytes.
|
||||||
maxInboundTransferRate = 0 # Maximum upload speed for broadcasters. This sucks right now. Set to 0 to disable.
|
maxInboundTransferRate = 0 # Maximum upload speed for broadcasters. This sucks right now. Set to 0 to disable.
|
||||||
|
|
||||||
|
def addThread():
|
||||||
|
global threadCount
|
||||||
|
with threadCountLock:
|
||||||
|
threadCount += 1
|
||||||
|
print("Thread opened. Threads: " +str(threadCount)+ " (Actual: " +str(threading.active_count())+ ")")
|
||||||
|
|
||||||
|
def removeThread():
|
||||||
|
global threadCount
|
||||||
|
with threadCountLock:
|
||||||
|
threadCount -= 1
|
||||||
|
print("Thread closed. Threads: " +str(threadCount)+ " (Actual: " +str(threading.active_count())+ ")")
|
||||||
|
|
||||||
def commandToList(cmd):
|
def commandToList(cmd):
|
||||||
args = []
|
args = []
|
||||||
cArg = ""
|
cArg = ""
|
||||||
@ -75,87 +88,62 @@ def commandToList(cmd):
|
|||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
class outThread(threading.Thread):
|
def closeConnection(connectionId):
|
||||||
def __init__(self,threadId,user):
|
if connectionId in connections:
|
||||||
threading.Thread.__init__(self)
|
del connections[connectionId]
|
||||||
self.threadId = threadId
|
|
||||||
self.queue = queue.Queue()
|
|
||||||
self.user = user
|
|
||||||
self.ignore = False
|
|
||||||
|
|
||||||
def closeConnection(self):
|
class outThread(threading.Thread):
|
||||||
with connectionsLock:
|
def __init__(self,connectionId):
|
||||||
if str(self.threadId) in connections:
|
threading.Thread.__init__(self)
|
||||||
try:
|
self.queue = queue.Queue()
|
||||||
connections[str(self.threadId)][0].close()
|
self.connectionId = connectionId
|
||||||
except Exception as e:
|
|
||||||
print("Warning, closing connection failed: " +str(e))
|
|
||||||
del connections[str(self.threadId)]
|
|
||||||
|
|
||||||
def getConnection(self):
|
def getConnection(self):
|
||||||
with connectionsLock:
|
with connectionsLock:
|
||||||
if str(self.threadId) in connections:
|
if self.connectionId in connections:
|
||||||
return connections[str(self.threadId)]
|
return connections[self.connectionId]["connection"]
|
||||||
|
return False
|
||||||
return False
|
|
||||||
|
|
||||||
def closeThread(self):
|
|
||||||
with threadsLock:
|
|
||||||
self.closeConnection()
|
|
||||||
if str(self.threadId) in outThreads: del outThreads[str(self.threadId)]
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
data = self.queue.get(timeout=15)
|
data = self.queue.get(timeout=15)
|
||||||
if type(data) == tuple:
|
connection = self.getConnection()
|
||||||
data[0](*data[1],**data[2])
|
if not connection:
|
||||||
if data[0] == self.closeThread: return
|
removeThread()
|
||||||
continue
|
return
|
||||||
self.getConnection()[0].sendall(data)
|
connection.sendall(data)
|
||||||
self.closeThread()
|
with connectionsLock: closeConnection(self.connectionId)
|
||||||
|
removeThread()
|
||||||
|
return
|
||||||
except:
|
except:
|
||||||
self.closeThread()
|
with connectionsLock: closeConnection(self.connectionId)
|
||||||
|
removeThread()
|
||||||
print("Thread closed - Exception:")
|
print("Thread closed - Exception:")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
class inThread(threading.Thread):
|
class inThread(threading.Thread):
|
||||||
def __init__(self,threadId):
|
def __init__(self,connectionId):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.threadId = threadId
|
self.connectionId = connectionId
|
||||||
|
|
||||||
def closeConnection(self):
|
|
||||||
with connectionsLock:
|
|
||||||
if str(self.threadId) in connections:
|
|
||||||
try:
|
|
||||||
connections[str(self.threadId)][0].close()
|
|
||||||
except:
|
|
||||||
print("warning, closing connection failed")
|
|
||||||
del connections[str(self.threadId)]
|
|
||||||
|
|
||||||
def getConnection(self):
|
def getConnection(self):
|
||||||
with connectionsLock:
|
with connectionsLock:
|
||||||
if str(self.threadId) in connections:
|
if self.connectionId in connections:
|
||||||
return connections[str(self.threadId)]
|
return connections[self.connectionId]["connection"]
|
||||||
|
return False
|
||||||
def closeThread(self,closeConnection = True):
|
|
||||||
with threadsLock:
|
|
||||||
if closeConnection:
|
|
||||||
for thread in outThreads:
|
|
||||||
thread = outThreads[thread]
|
|
||||||
if thread.user == self.user:
|
|
||||||
thread.queue.put((thread.closeThread,[],{}))
|
|
||||||
|
|
||||||
self.closeConnection()
|
|
||||||
|
|
||||||
if str(self.threadId) in inThreads: del inThreads[str(self.threadId)]
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
data = self.getConnection()[0].recv(1000)
|
connection = self.getConnection()
|
||||||
|
if not connection:
|
||||||
|
removeThread()
|
||||||
|
return
|
||||||
|
data = connection.recv(1000)
|
||||||
if data == b"":
|
if data == b"":
|
||||||
self.closeThread()
|
with connectionsLock: closeConnection(self.connectionId)
|
||||||
print("Thread closed - Client disconnected.")
|
print("Thread closed - Client disconnected.")
|
||||||
|
removeThread()
|
||||||
return
|
return
|
||||||
data = data.decode("utf-8")
|
data = data.decode("utf-8")
|
||||||
while data[-1] == " ": data = data[:-1]
|
while data[-1] == " ": data = data[:-1]
|
||||||
@ -171,8 +159,9 @@ class inThread(threading.Thread):
|
|||||||
userPath = p(sp,"users",user+ ".ini")
|
userPath = p(sp,"users",user+ ".ini")
|
||||||
with fileLock:
|
with fileLock:
|
||||||
if not os.path.isfile(userPath):
|
if not os.path.isfile(userPath):
|
||||||
self.closeThread()
|
with connectionsLock: closeConnection(self.connectionId)
|
||||||
print("Thread closed - Invalid user given: " +user)
|
print("Thread closed - Invalid user given: " +user)
|
||||||
|
removeThread()
|
||||||
return
|
return
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
@ -180,55 +169,73 @@ class inThread(threading.Thread):
|
|||||||
|
|
||||||
if cmd == "watch":
|
if cmd == "watch":
|
||||||
if cmd in config and "pass" in config[cmd] and config[cmd]["pass"] != "" and config[cmd]["pass"] != password:
|
if cmd in config and "pass" in config[cmd] and config[cmd]["pass"] != "" and config[cmd]["pass"] != password:
|
||||||
self.closeThread()
|
with connectionsLock: closeConnection(self.connectionId)
|
||||||
print("Thread closed - Invalid password given for user: " +user)
|
print("Thread closed - Invalid password given for user: " +user)
|
||||||
|
removeThread()
|
||||||
return
|
return
|
||||||
|
|
||||||
with threadsLock:
|
with connectionsLock:
|
||||||
thread = outThread(self.threadId,self.user)
|
if not self.connectionId in connections:
|
||||||
outThreads[str(self.threadId)] = thread
|
removeThread()
|
||||||
|
return
|
||||||
|
connections[self.connectionId]["action"] = "watch"
|
||||||
|
connections[self.connectionId]["user"] = user
|
||||||
|
thread = outThread(self.connectionId)
|
||||||
|
connections[self.connectionId]["outThread"] = thread
|
||||||
thread.start()
|
thread.start()
|
||||||
|
addThread()
|
||||||
self.closeThread(False)
|
connections[self.connectionId]["inThread"] = False
|
||||||
return
|
removeThread()
|
||||||
|
return
|
||||||
|
|
||||||
if cmd == "broadcast":
|
if cmd == "broadcast":
|
||||||
if cmd in config and "pass" in config[cmd] and config[cmd]["pass"] != "" and config[cmd]["pass"] != password:
|
if cmd in config and "pass" in config[cmd] and config[cmd]["pass"] != "" and config[cmd]["pass"] != password:
|
||||||
self.closeThread()
|
with connectionsLock: closeConnection(self.connectionId)
|
||||||
print("Thread closed - Invalid password given for user: " +user)
|
print("Thread closed - Invalid password given for user: " +user)
|
||||||
|
removeThread()
|
||||||
return
|
return
|
||||||
|
|
||||||
with threadsLock:
|
with connectionsLock:
|
||||||
deleteList = []
|
deleteList = []
|
||||||
for threadId in inThreads:
|
for connectionId in connections:
|
||||||
if threadId == str(self.threadId): continue
|
if connectionId == self.connectionId: continue
|
||||||
thread = inThreads[threadId]
|
if connections[connectionId]["action"] != "broadcast": continue
|
||||||
thread.closeConnection()
|
if connections[connectionId]["user"] != user: continue
|
||||||
deleteList.append(threadId)
|
deleteList.append(connectionId)
|
||||||
|
|
||||||
for threadId in deleteList:
|
for connectionId in deleteList:
|
||||||
del inThreads[threadId]
|
closeConnection[connectionId]
|
||||||
|
|
||||||
|
connections[connectionId]["action"] = "broadcast"
|
||||||
|
connections[connectionId]["user"] = user
|
||||||
|
|
||||||
if maxInboundTransferRate > 0: startTime = time.time()
|
if maxInboundTransferRate > 0: startTime = time.time()
|
||||||
while True:
|
while True:
|
||||||
data = self.getConnection()[0].recv(bufferSize)
|
connection = self.getConnection()
|
||||||
|
if not connection:
|
||||||
|
removeThread()
|
||||||
|
return
|
||||||
|
data = connection.recv(bufferSize)
|
||||||
if data == b"":
|
if data == b"":
|
||||||
self.closeThread()
|
with connectionsLock: closeConnection(self.connectionId)
|
||||||
print("Thread closed - Client disconnected.")
|
print("Thread closed - Client disconnected.")
|
||||||
|
removeThread()
|
||||||
return
|
return
|
||||||
|
|
||||||
with threadsLock:
|
with connectionsLock:
|
||||||
for thread in outThreads:
|
for connectionId in connections:
|
||||||
thread = outThreads[thread]
|
connectionData = connections[connectionId]
|
||||||
if thread.user == user:
|
thread = connectionData["outThread"]
|
||||||
accumulatedData = thread.queue.qsize() * bufferSize
|
if not thread: continue
|
||||||
if accumulatedData > maxAccumulatedData and not thread.ignore:
|
if connectionData["user"] != user: continue
|
||||||
thread.ignore = True
|
accumulatedData = thread.queue.qsize() * bufferSize
|
||||||
thread.queue.put((thread.closeThread,[],{}))
|
if accumulatedData > maxAccumulatedData:
|
||||||
thread.closeConnection()
|
print("Thread closed - Too much accumulated data.")
|
||||||
print("Thread closed - Too much accumulated data.")
|
closeConnection(connectionId)
|
||||||
else:
|
removeThread()
|
||||||
thread.queue.put(data)
|
return
|
||||||
|
|
||||||
|
thread.queue.put(data)
|
||||||
|
|
||||||
if maxInboundTransferRate > 0:
|
if maxInboundTransferRate > 0:
|
||||||
endTime = time.time()
|
endTime = time.time()
|
||||||
@ -244,11 +251,13 @@ class inThread(threading.Thread):
|
|||||||
|
|
||||||
startTime = endTime
|
startTime = endTime
|
||||||
|
|
||||||
self.closeThread()
|
with connectionsLock: closeConnection(self.connectionId)
|
||||||
|
removeThread()
|
||||||
return
|
return
|
||||||
except:
|
except:
|
||||||
|
with connectionsLock: closeConnection(self.connectionId)
|
||||||
|
removeThread()
|
||||||
print("Thread closed - Exception:")
|
print("Thread closed - Exception:")
|
||||||
self.closeThread()
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
class debugThread(threading.Thread):
|
class debugThread(threading.Thread):
|
||||||
@ -257,7 +266,7 @@ class debugThread(threading.Thread):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while True:
|
while True:
|
||||||
with threadsLock:
|
with connectionsLock:
|
||||||
print("\n---\n")
|
print("\n---\n")
|
||||||
print("Threads - IN: " +str(len(inThreads)))
|
print("Threads - IN: " +str(len(inThreads)))
|
||||||
print("Threads - OUT: " +str(len(outThreads)))
|
print("Threads - OUT: " +str(len(outThreads)))
|
||||||
@ -294,15 +303,15 @@ def readConfig():
|
|||||||
serverAddr = tuple(serverAddrSplit)
|
serverAddr = tuple(serverAddrSplit)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global threadId
|
global connectionsId
|
||||||
readConfig()
|
readConfig()
|
||||||
|
|
||||||
serverSocket.bind(serverAddr)
|
serverSocket.bind(serverAddr)
|
||||||
serverSocket.listen(1024)
|
serverSocket.listen(1024)
|
||||||
|
|
||||||
# DEBUG
|
# DEBUG
|
||||||
debug = debugThread()
|
#debug = debugThread()
|
||||||
debug.start()
|
#debug.start()
|
||||||
# DEBUG END
|
# DEBUG END
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@ -312,25 +321,34 @@ def main():
|
|||||||
with connectionsLock:
|
with connectionsLock:
|
||||||
clientCount = 0
|
clientCount = 0
|
||||||
ipClientCount = 0
|
ipClientCount = 0
|
||||||
for connId in connections:
|
for connectionId in connections:
|
||||||
clientCount += 1
|
clientCount += 1
|
||||||
conn = connections[connId]
|
if connections[connectionId]["address"][0] == address[0]:
|
||||||
if conn[1][0] == address[0]:
|
|
||||||
ipClientCount += 1
|
ipClientCount += 1
|
||||||
|
|
||||||
if clientCount + 1 > maxClients or ipClientCount + 1 > maxClientsPerIP:
|
if clientCount + 1 > maxClients:
|
||||||
print("Connection closed - same IP connected too many times.")
|
print("Connection closed - too many clients.")
|
||||||
connection.close()
|
closeConnection(connectionId)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with threadsLock:
|
if ipClientCount + 1 > maxClientsPerIP:
|
||||||
threadId += 1
|
print("Connection closed - same IP connected too many times.")
|
||||||
with connectionsLock:
|
closeConnection(connectionId)
|
||||||
connections[str(threadId)] = (connection,address)
|
continue
|
||||||
|
|
||||||
thread = inThread(threadId)
|
connectionsId += 1
|
||||||
inThreads[str(threadId)] = thread
|
threadIn = inThread(str(connectionsId))
|
||||||
thread.start()
|
connections[str(connectionsId)] = {
|
||||||
|
"connection": connection,
|
||||||
|
"address": address,
|
||||||
|
"inThread": threadIn,
|
||||||
|
"outThread": False,
|
||||||
|
"action": False,
|
||||||
|
"user": False
|
||||||
|
}
|
||||||
|
|
||||||
|
threadIn.start()
|
||||||
|
addThread()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
Loading…
Reference in New Issue
Block a user