Flash socket policy server in Python based on gevent

Currently, I am looking into gevent — a nicely performing networking library for Python, based on the brilliant idea of greenlets. I try to use this for WebSocket communication with browsers. As of today, WebSockets are still not available or disabled in some browsers. That’s why there are Javascript implementations like web-socket-js providing a transparent “Flashbridge” as a fallback for the WebSocket communication. But the Flash plugin in the client’s browser does not simply communicate with any server on any port in the world. As a first step, it always tries to receive a so-called socket policy file from the same server the SWF file was received from; on port 843. This policy file tells the client from whom he is allowed to receive data. Today, I present a simple server based on gevent providing this policy file for connecting Flash clients.

By using gevent, you automatically get one of the highest performing Python servers you can get for this purpose. Due to the greenlet concept, it is able to handle a huge amount of concurrent connections without any threading overhead. Due to benchmarks like this, the server should be faster than comparable Python solutions (based on e.g. Twisted or Eventlet) while almost reaching the level of optimized C/C++ solutions. Of course, all this performance is not really necessary for a Flash policy server, but it is good to know what we are dealing with.

Now, the code. It is already “bloated” with comments and logging functionality. Due to the use of gevent, the server code itself is very simple:

#!/usr/bin/env python
 
# Flash access policy server based on gevent
# Jan-Philip Gehrcke, June 2011
 
# Listen on port 843; send acess policy to client; disconnect.
 
 
from gevent.server import StreamServer
import datetime
import socket
 
 
# Should we log something? Where to?
LOG = 1
LOGFILE = "flash_access_policy_server.log"
 
# The policy that is sent to the clients.
POLICY = """<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>\0"""
 
# The string the client has to send in order to receive the policy.
POLICYREQUEST = "<policy-file-request/>"
 
 
# This function is called for each incoming connection
# (in a non-blocking fashion in a greenlet)
def client_handle(sock, address):
    log("%s:%s: Connection accepted." % address)
    # send and read functions should not wait longer than three seconds
    sock.settimeout(3)
    try:
        # try to receive at most 128 bytes (`POLICYREQUEST` is shorter)
        input = sock.recv(128)
        if input.startswith(POLICYREQUEST):
            sock.sendall(POLICY)
            log("%s:%s: Policy sent. Closing connection." % address)
        else:
            log("%s:%s: Crap received. Closing connection." % address)    
    except socket.timeout:
        log("%s:%s: Timed out. Closing." % address)
    sock.close()
 
 
# Write `msg` to file and stdout, prepended by a date/time string
def log(msg):
    if LOG:
        l = "%s: %s" % (datetime.datetime.now().isoformat(), msg)
        lf.write("%s\n" % l)
        print l
 
 
if __name__ == '__main__':
    if LOG:
        lf = open(LOGFILE, "a")
    server = StreamServer(('0.0.0.0', 843), client_handle)
    log('Starting server...')
    server.serve_forever()

Note that the policy in this case is not very sophisticated and basically allows everything;-)

One Pingback/Trackback

  • Pingback: The best and simplest tools to create a basic WebSocket application with Flash fallback and Python on the server side » gehrcke.de

  • http://www.google.com/ Benon

    That’s a smart aneswr to a difficult question.

  • Nelson

    Hello!

    I have a problem that is breaking my head over a week!

    I have a Flash game that works under Python.

    The game works fine in localhost, but doesn’t work if

    someone try to play it from another computer. You can access mysql,

    login into the server, but can’t play.

    When play it in localhost the firestarter get first a 127.0.01 entry in 80 port, unknow service.

    Then when the game starts the entry change to 127.0.0.1 2001, unknow service.

    When other computer try to play, get a entry in 80 port, and stops there.

    Below some file parts.

    ———–#—————-

    This is the config.py

    mysql_host = ‘localhost’

    mysql_user = ‘root’

    mysql_pass = ‘pass’

    root_host = ‘localhost’

    policy_line = ‘

    ————#——————-

    The init.py

    from policy_server import PolicyFactory

    from game_server import gameFactory

    from twisted.internet import reactor

    def main():

    print ‘Server Started…’

    reactor.listenTCP(843, PolicyFactory())

    GameServer = GameFactory(‘localhost’, ‘pt_br’)

    reactor.listenTCP(1024, gameServer)

    reactor.listenTCP(2001, gameServer)

    reactor.listenTCP(3001, gameServer)

    reactor.listenTCP(4001, gameServer)

    reactor.listenTCP(6001, gameServer)

    reactor.listenTCP(7001, gameServer)

    reactor.listenTCP(8001, gameServer)

    reactor.listenTCP(9001, gameServer)

    reactor.listenTCP(9002, gameServer)

    reactor.listenTCP(9092, gameServer)

    reactor.run()

    if (__name__ == ‘__main__’):

    main()

    —————-#————————-

    crossdomain.xml

    ————–#————————————–

    THX