[Server-devel] [PATCH 1/2] xs-activation-tcpserver: use non-blocking reads

Daniel Drake dsd at laptop.org
Thu Dec 29 15:55:33 EST 2011


Using non-blocking reads cleans up the code a little and paves the
way for easy addition of further request formats.

The only functional change here is the logging of unknown requests
(truncated to 48 characters max) - the server should otherwise
behave as before.
---
 xs-activation-tcpserver.py |   77 +++++++++++++++++++++++--------------------
 1 files changed, 41 insertions(+), 36 deletions(-)

diff --git a/xs-activation-tcpserver.py b/xs-activation-tcpserver.py
index 40f7424..942eaf1 100755
--- a/xs-activation-tcpserver.py
+++ b/xs-activation-tcpserver.py
@@ -8,6 +8,8 @@ import sys, os.path
 from subprocess import *
 import re
 import oat
+import select
+import fcntl
 
 # Setup logging to logger.
 # The logger process will be reaped
@@ -19,6 +21,11 @@ sys.stderr = loggersocket
 
 myoat = oat.oat()
 
+# make stdin a non-blocking file
+fd = sys.stdin.fileno()
+fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+
 def log_error(str):
     sys.stderr.write(str + "\n")
 
@@ -40,13 +47,7 @@ def check_stolen(sn):
         sys.stderr.write("STOLEN: %s\n" % sn)
         exit()
 
-######## Main ###########
-
-# first we read 11 chars
-req = sys.stdin.read(11)
-
-if re.match('^[A-Z0-9]{11}$', req):
-
+def send_lease(req):
     # naked sn
     sn = req
 
@@ -70,37 +71,41 @@ if re.match('^[A-Z0-9]{11}$', req):
     sys.stdout.write("UNKNOWN\n")
     exit()
 
-else:
-    m = re.match('^([a-zA-Z0-9]+): ', req)
-    if not m:
-        log_error("cannot understand input: " + req)
+def send_time(req):
+    # remove time01: prefix
+    req = req[8:]
+
+    # read params
+    (sn, nonce) = req.split(' ')
+    if not (len(sn)==11 and len(nonce)==22):
+        log_error("cannot understand input: " + params)
         exit(1)
 
-    cmd = m.group(1)
-    paramhead = req[len(m.group(0)):]
-
-    if cmd == 'time01':
-        # read the remainder of the 11 char sn
-        paramtail = sys.stdin.read(11+1+22 - len(paramhead))
-        params = paramhead+paramtail
-        (sn, nonce) = params.split(' ')
-        if not (len(sn)==11 and len(nonce)==22):
-            log_error("cannot understand input: " + params)
-            exit(1)
-
-        sys.stderr.write("Time request for %s\n" % sn)
-        check_stolen(sn)
-        timemsg = myoat.get_time(sn, nonce)
-
-        if timemsg:
-            # log
-            sys.stdout.write(timemsg)
-            exit()
-        else:
-            sys.stderr.write("Could not serve time request for %s - probable cause: no lease available\n" % sn)
+    sys.stderr.write("Time request for %s\n" % sn)
+    check_stolen(sn)
+    timemsg = myoat.get_time(sn, nonce)
 
+    if timemsg:
+        # log
+        sys.stdout.write(timemsg)
+        exit()
     else:
-        # unknown command?
-        log_error("unknown command: " + cmd)
-        exit(1)
+        sys.stderr.write("Could not serve time request for %s - probable cause: no lease available\n" % sn)
+
+######## Main ###########
+
+# wait for data to arrive
+if not select.select([sys.stdin], [], [], 30):
+    log_error("Timeout receiving data")
+    exit(1)
+
+req = sys.stdin.read()
+if re.match('^[A-Z0-9]{11}$', req):
+    send_lease(req)
+elif req.startswith('time01: '):
+    send_time(req)
+else:
+    # unknown command? log up to 48 chars to minimize chance of DoS flood
+    log_error("unknown request: " + req[:48])
+    exit(1)
 
-- 
1.7.7.4



More information about the Server-devel mailing list