Fixed too-many-open-files ddos
This commit is contained in:
parent
5a4cb85bea
commit
ab69b8f86f
2 changed files with 71 additions and 40 deletions
42
brain.py
42
brain.py
|
|
@ -2,6 +2,8 @@ import pixelflut
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
pixelcount = 0
|
||||||
|
|
||||||
def guess_IP():
|
def guess_IP():
|
||||||
import socket
|
import socket
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
|
@ -17,13 +19,14 @@ port = 1234
|
||||||
text = 'P1XELFLUT! v%s (%d)\n' % (
|
text = 'P1XELFLUT! v%s (%d)\n' % (
|
||||||
pixelflut.__version__,
|
pixelflut.__version__,
|
||||||
os.stat(__file__).st_mtime)
|
os.stat(__file__).st_mtime)
|
||||||
text += 'Connect to %s:%d\n\n' % (IP, port)
|
text += '$ echo "HELP" | netcat %s %d\n' % (IP, port)
|
||||||
text += '>>> HELP\n'
|
text += 'https://github.com/defnull/pixelflut'
|
||||||
text += '>>> SIZE\n'
|
|
||||||
text += '>>> TEXT x y text\n'
|
help = 'Commands:'
|
||||||
text += '>>> PX x y [RRGGBB (hex)]\n'
|
help += '>>> HELP\n'
|
||||||
text += '... and more ...\n\n'
|
help += '>>> SIZE\n'
|
||||||
text += 'H A C K O N\n'
|
help += '>>> TEXT x y text\n'
|
||||||
|
help += '>>> PX x y [RRGGBB (hex)]\n'
|
||||||
|
|
||||||
@on('LOAD')
|
@on('LOAD')
|
||||||
def callback(c):
|
def callback(c):
|
||||||
|
|
@ -41,7 +44,7 @@ def on_resize(c):
|
||||||
@on('CONNECT')
|
@on('CONNECT')
|
||||||
def on_connect(c, client):
|
def on_connect(c, client):
|
||||||
pass
|
pass
|
||||||
#print c.clients.keys()
|
#print client
|
||||||
|
|
||||||
@on('KEYDOWN-c')
|
@on('KEYDOWN-c')
|
||||||
def on_key_c(c):
|
def on_key_c(c):
|
||||||
|
|
@ -60,12 +63,13 @@ def on_key_s(c):
|
||||||
|
|
||||||
@on('COMMAND-HELP')
|
@on('COMMAND-HELP')
|
||||||
def on_help(canvas, client):
|
def on_help(canvas, client):
|
||||||
client.send(text)
|
client.send(help)
|
||||||
|
|
||||||
@on('COMMAND-TEXT')
|
@on('COMMAND-TEXT')
|
||||||
def on_text(canvas, client, x, y, *words):
|
def on_text(canvas, client, x, y, *words):
|
||||||
x, y = int(x), int(y)
|
x, y = int(x), int(y)
|
||||||
canvas.text(x, y, ' '.join(words), delay=0.1)
|
text = ' '.join(words)[:200]
|
||||||
|
canvas.text(x, y, text, delay=0.5)
|
||||||
|
|
||||||
@on('COMMAND-SIZE')
|
@on('COMMAND-SIZE')
|
||||||
def on_size(canvas, client):
|
def on_size(canvas, client):
|
||||||
|
|
@ -77,20 +81,24 @@ def on_quit(canvas, client):
|
||||||
|
|
||||||
@on('COMMAND-PX')
|
@on('COMMAND-PX')
|
||||||
def on_px(canvas, client, x, y, color=None):
|
def on_px(canvas, client, x, y, color=None):
|
||||||
|
global pixelcount
|
||||||
|
pixelcount += 1
|
||||||
client.last_pixel = time.time()
|
client.last_pixel = time.time()
|
||||||
x, y = int(x), int(y)
|
x, y = int(x), int(y)
|
||||||
if color:
|
if color:
|
||||||
c = int(color, 16)
|
c = int(color, 16)
|
||||||
if c <= 16777215:
|
if len(color) == 6:
|
||||||
r = (c & 0xff0000) >> 16
|
r = (c & 0xff0000) >> 16
|
||||||
g = (c & 0x00ff00) >> 8
|
g = (c & 0x00ff00) >> 8
|
||||||
b = c & 0x0000ff
|
b = c & 0x0000ff
|
||||||
a = 0xff
|
a = 0xff
|
||||||
else:
|
elif len(color) == 8:
|
||||||
r = (c & 0xff000000) >> 24
|
r = (c & 0xff000000) >> 24
|
||||||
g = (c & 0x00ff0000) >> 16
|
g = (c & 0x00ff0000) >> 16
|
||||||
b = (c & 0x0000ff00) >> 8
|
b = (c & 0x0000ff00) >> 8
|
||||||
a = c & 0x000000ff
|
a = c & 0x000000ff
|
||||||
|
else:
|
||||||
|
return
|
||||||
canvas.set_pixel(x, y, r, g, b, a)
|
canvas.set_pixel(x, y, r, g, b, a)
|
||||||
else:
|
else:
|
||||||
r,g,b,a = canvas.get_pixel(x,y)
|
r,g,b,a = canvas.get_pixel(x,y)
|
||||||
|
|
@ -99,10 +107,16 @@ def on_px(canvas, client, x, y, color=None):
|
||||||
|
|
||||||
|
|
||||||
last_save = 0
|
last_save = 0
|
||||||
|
|
||||||
@on('TICK')
|
@on('TICK')
|
||||||
def on_tick(canvas, dt):
|
def on_tick(canvas, dt):
|
||||||
global last_save
|
global last_save, pixelcount
|
||||||
|
canvas.text(5, 5, text, delay=0)
|
||||||
|
|
||||||
if time.time() > last_save:
|
if time.time() > last_save:
|
||||||
last_save = time.time() + 5
|
last_save = time.time() + 5
|
||||||
canvas.save_as('save/mov_%d.png' % last_save)
|
canvas.save_as('save/mov_%d.png' % last_save)
|
||||||
canvas.text(5, 5, text, delay=0)
|
print len(canvas.clients)
|
||||||
|
canvas.text(5, 200, 'px/s %d' % (pixelcount/5), delay=0)
|
||||||
|
canvas.text(5, 208, 'Connections %d' % len([c for c in canvas.clients.values() if c.socket]), delay=0)
|
||||||
|
pixelcount = 0
|
||||||
|
|
|
||||||
55
pixelflut.py
55
pixelflut.py
|
|
@ -1,11 +1,11 @@
|
||||||
#coding: utf8
|
#coding: utf8
|
||||||
|
|
||||||
__version__ = '0.5'
|
__version__ = '0.6'
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from gevent import spawn, sleep as gsleep
|
from gevent import spawn, sleep as gsleep
|
||||||
from gevent.server import StreamServer
|
from gevent.socket import socket
|
||||||
from gevent.coros import Semaphore
|
from gevent.coros import Semaphore, RLock
|
||||||
from gevent.queue import Queue
|
from gevent.queue import Queue
|
||||||
from collections import deque
|
from collections import deque
|
||||||
import pygame
|
import pygame
|
||||||
|
|
@ -33,6 +33,7 @@ class Client(object):
|
||||||
# And this is used to limit clients to X messages per tick
|
# And this is used to limit clients to X messages per tick
|
||||||
# We start at 0 (instead of x) to add a reconnect-penalty.
|
# We start at 0 (instead of x) to add a reconnect-penalty.
|
||||||
self.limit = Semaphore(0)
|
self.limit = Semaphore(0)
|
||||||
|
self.lock = RLock()
|
||||||
|
|
||||||
def send(self, line):
|
def send(self, line):
|
||||||
self.sendbuffer.append(line.strip() + '\n')
|
self.sendbuffer.append(line.strip() + '\n')
|
||||||
|
|
@ -42,16 +43,21 @@ class Client(object):
|
||||||
self.sendbuffer.append(line.strip() + '\n')
|
self.sendbuffer.append(line.strip() + '\n')
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
|
with self.lock:
|
||||||
if self.socket:
|
if self.socket:
|
||||||
self.socket.close()
|
socket = self.socket
|
||||||
self.socket = None
|
self.socket = None
|
||||||
|
socket.close()
|
||||||
|
log.info('Disconnect')
|
||||||
|
|
||||||
def serve(self, socket):
|
def serve(self, socket):
|
||||||
|
with self.lock:
|
||||||
self.socket = socket
|
self.socket = socket
|
||||||
sendall = self.socket.sendall
|
sendall = self.socket.sendall
|
||||||
readline = self.socket.makefile().readline
|
readline = self.socket.makefile().readline
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while True:
|
while self.socket:
|
||||||
self.limit.acquire()
|
self.limit.acquire()
|
||||||
# Idea: Send first, receive later. If the client is to
|
# Idea: Send first, receive later. If the client is to
|
||||||
# slow to get the send-buffer empty, he cannot send.
|
# slow to get the send-buffer empty, he cannot send.
|
||||||
|
|
@ -64,8 +70,9 @@ class Client(object):
|
||||||
command = arguments.pop(0)
|
command = arguments.pop(0)
|
||||||
try:
|
try:
|
||||||
self.canvas.fire('COMMAND-%s' % command.upper(), self, *arguments)
|
self.canvas.fire('COMMAND-%s' % command.upper(), self, *arguments)
|
||||||
except TypeError, e:
|
except Exception, e:
|
||||||
self.nospam('ERROR %r :(' % e)
|
socket.send('ERROR %r :(' % e)
|
||||||
|
break
|
||||||
finally:
|
finally:
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
|
|
||||||
|
|
@ -95,21 +102,31 @@ class Canvas(object):
|
||||||
self.font = pygame.font.Font(None, 17)
|
self.font = pygame.font.Font(None, 17)
|
||||||
|
|
||||||
def serve(self, host, port):
|
def serve(self, host, port):
|
||||||
self.server = StreamServer((host, port), self.make_client)
|
self.host = host
|
||||||
self.server.start()
|
self.port = port
|
||||||
return spawn(self._loop)
|
|
||||||
|
spawn(self._loop)
|
||||||
|
|
||||||
|
self.socket = socket()
|
||||||
|
self.socket.bind((host, port))
|
||||||
|
self.socket.listen(500)
|
||||||
|
while True:
|
||||||
|
sock, addr = self.socket.accept()
|
||||||
|
ip, port = addr
|
||||||
|
|
||||||
|
log.info('Connect %s:%d', ip, port)
|
||||||
|
|
||||||
def make_client(self, socket, address):
|
|
||||||
ip = address[0]
|
|
||||||
client = self.clients.get(ip)
|
client = self.clients.get(ip)
|
||||||
if client:
|
if not client:
|
||||||
client.disconnect()
|
client = self.clients[ip] = Client(self)
|
||||||
else:
|
|
||||||
self.clients[ip] = client = Client(self)
|
|
||||||
|
|
||||||
|
client.disconnect()
|
||||||
|
spawn(self.handle_client, client, sock)
|
||||||
|
|
||||||
|
def handle_client(self, client, sock):
|
||||||
try:
|
try:
|
||||||
self.fire('CONNECT', client)
|
self.fire('CONNECT', client)
|
||||||
client.serve(socket) # This blocks until ready
|
client.serve(sock) # This blocks until ready
|
||||||
self.fire('DISCONNECT', client)
|
self.fire('DISCONNECT', client)
|
||||||
finally:
|
finally:
|
||||||
client.disconnect()
|
client.disconnect()
|
||||||
|
|
@ -214,7 +231,7 @@ class Canvas(object):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
logging.basicConfig()
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
import optparse
|
import optparse
|
||||||
parser = optparse.OptionParser("usage: %prog [options] brain_script")
|
parser = optparse.OptionParser("usage: %prog [options] brain_script")
|
||||||
|
|
@ -229,7 +246,7 @@ if __name__ == '__main__':
|
||||||
parser.error("incorrect number of arguments")
|
parser.error("incorrect number of arguments")
|
||||||
|
|
||||||
canvas = Canvas()
|
canvas = Canvas()
|
||||||
task = canvas.serve(options.hostname, options.portnum)
|
task = spawn(canvas.serve, options.hostname, options.portnum)
|
||||||
|
|
||||||
brainfile = args[0]
|
brainfile = args[0]
|
||||||
mtime = 0
|
mtime = 0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue