From 1207c6b225365c9aeeed26e5c03044f3d7eef845 Mon Sep 17 00:00:00 2001 From: Christian Damken Date: Fri, 26 Apr 2013 12:55:37 +0200 Subject: [PATCH] - cleaned class argparser - commented and cleaned asrc-server.py - renamed includes/content.py to includes/comm.py - renamed class content to comm - made some vars (aliases, server_version, protocol_version, verbiosity) global in class comm - added init() to class comm for setting lobal vars - moved motd() from asrc-server-py to class comm - conformed comm.motd() to reference - added comm.header() for building the headers - added includes/statuscodes.py with class statuscodes with dict description for storing the status codes and their description - added docstrings --- asrc-server.py | 364 +++++++++++++------------------- doc/protocol_reference.odt | Bin 19665 -> 19407 bytes include/__init__.py | 2 +- include/argparser.py | 143 +++++++------ include/{content.py => comm.py} | 57 ++++- include/statuscodes.py | 37 ++++ 6 files changed, 306 insertions(+), 297 deletions(-) rename include/{content.py => comm.py} (64%) create mode 100644 include/statuscodes.py diff --git a/asrc-server.py b/asrc-server.py index a9211be..aa329d7 100755 --- a/asrc-server.py +++ b/asrc-server.py @@ -25,7 +25,7 @@ # aSRC (Aliased Server Remote Control) # - SERVER - # -# program version: 0.0.0.20130424 +# program version: 0.0.0.20130426 # protocol version: 0.2.20130423 # # @@ -35,243 +35,175 @@ import sys, os, socket, socketserver, threading, time -def motd(): - return MOTD - - -#def content(client_address, data): - #ret = "" - - #ret = ret +\ - #"{BEGIN}\n"\ - #"asrcp" + ProtocolVersion + "\n" - - ## Look if the received message is an - ## valid alias or a predefined command - - ## if it's 'version', return the server and protocol version - #if data == "version": - - #if VERBOSITY >= 2: print("Got valid service command from" - #+ str(client_address) + ": ", data) - - #ret = ret +\ - #"202 Valid Service Command\n"\ - #"002 Version\n"\ - #"ServerVersion:" + ServerVersion + "\n"\ - #"ProtocolVersion:" + ProtocolVersion + "\n" - - ## if it's 'help', give a little help - #elif data == 'help': - - #if VERBOSITY >= 2: print("Got valid command from" - #+ str(client_address) + ": ", data) - - ## send status code - #ret = ret + "202 Valid Service Command\n\n" - - ## send the list of aliases - #ret = ret + "Aviable aliases:\n" - #for i in aliases.keys(): - #ret = ret + str(i) + "\n" - - ## if it's a valid userdefined command - #elif data in aliases: - - ## send status code - #ret = ret + "201 Valid Command\n\n" - - ## ohmagawd! a debug message!!1! - #if VERBOSITY >= 2: print("Got valid command from" - #+ str(client_address) + ": ", data) - - ## execute the aliased command - #g_dict, l_dict = {}, {} - #exec(str(aliases[data]), g_dict, l_dict) - - ## send may contain data to send to the client - #if l_dict["send"]: - #content = str(l_dict["send"]).replace('{', '\{') - #content = content.replace('}', '\}') - - #ret = ret + content + "\n" - - ## ALL IS LOST!!1! this has to be invalid! - #else: - - ## send status code - #ret = ret + "203 Invalid Command\n" - - #if VERBOSITY >= 2: print("Got invalid command from", - #str(client_address), ": ", data) - - #ret = ret + "{END}\n" - - #return ret - - class ThreadedRequestHandler(socketserver.StreamRequestHandler): - - def handle(self): - - # Set time for timeout in seconds - self.timeout = TIMEOUT - - # Print a line with the adress of the connected client - if VERBOSITY >=3: - print("Client connected: " + str(self.client_address)) - - # send header line 1 - self.request.sendall(bytes - ("asrpc " + ProtocolVersion + "\n", ENCODING)) - - # send motd - self.request.sendall(bytes(motd() + "\n", ENCODING)) - - # Receive data - self.data = str(self.rfile.readline().strip(), ENCODING) - - # content handler - self.request.sendall(bytes( - content.handler(str(self.client_address), self.data, aliases, - ServerVersion, ProtocolVersion, VERBOSITY), ENCODING)) + + def handle(self): + """ + Handles incoming connections + """ + + # Set time for timeout in seconds + self.timeout = TIMEOUT + + # Print a line with the adress of the connected client + if VERBOSITY >=3: + print("Client connected: " + str(self.client_address)) + + # send motd + self.request.sendall(comm.motd(MOTD) + "\n", ENCODING)) + + # Receive data + self.data = str(self.rfile.readline().strip(), ENCODING) + + # content handler + self.request.sendall(bytes( + comm.handler(str(self.client_address), self.data), ENCODING)) class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): - pass + pass def main(): - global VERBOSITY, HOST, PORT, TIMEOUT, ENCODING - - from include import argparser, content - - parser = argparser - args = parser.parse(ServerVersion, ProtocolVersion) - - if os.path.exists("pid"): - if args.delete_pid_file: os.remove("pid") - elif args.allow_multiple_instances: pass - else: - print( - "\npid file already exists\n"\ - "If the server didn't shut down correctly, just delete this file "\ - "or pass -n\n"\ - "If you want to start multiple instances, pass -m\n") - return 1 - - print(args) - - if args.host: HOST = args.host - if args.port: PORT = args.port - if args.timeout: TIMEOUT = args.timeout - if args.encoding: ENCODING = args.encoding - if args.verbosity: VERBOSITY = args.verbosity - - # write pid file - pidf = open("pid", 'w') - pidf.write(str(os.getpid())) - pidf.close() - - print("aSRC Server\n"\ - "Server version: " + ServerVersion + "\n"\ - "Protocol version: " + ProtocolVersion + "\n\n"\ - "To stop the server, press Ctrl-C\n") - - try: - if VERBOSITY >= 1: print("Initializing server...") - # Create server - server = ThreadedTCPServer((HOST, PORT), ThreadedRequestHandler) - - if VERBOSITY >= 1: print("Starting server on", - server.server_address[0], "port", server.server_address[1], "...") - # Start a thread with the server -- that thread will then start one - # more thread for each request - ServerThread = threading.Thread(target = server.serve_forever) - - # Exit the server thread when the main thread terminates - ServerThread.daemon = True - ServerThread.start() - - while True: - time.sleep(10) - - except KeyboardInterrupt: - print("\nGot Ctrl-C, shutting down server...") - - try: - server.shutdown() - os.remove("pid") - except: print("Failed to shutdown server correctly, "\ - "socket may be still in use or wasn't even started:", - sys.exc_info()) - #except: - # print("\nAn error occured:\n", sys.exc_info(), "\n") - - if VERBOSITY >= 3: input("Press Enter to continue\n") - return 0 + # import global settings + global VERBOSITY, HOST, PORT, TIMEOUT, ENCODING + + from include import argparser, comm + + comm.init(ServerVersion, ProtocolVersion, VERBOSITY, aliases) + + # parse arguments + parser = argparser + args = parser.parse(ServerVersion, ProtocolVersion) + + # look for pid file + if os.path.exists("pid"): + # remove, ... + if args.delete_pid_file: os.remove("pid") + # ... ignore ... + elif args.allow_multiple_instances: pass + # ... or exit + else: + print( + "\npid file already exists\n"\ + "If the server didn't shut down correctly, "\ + "just delete this file or pass -n\n"\ + "If you want to start multiple instances, pass -m\n") + return 1 + + # set settings if command line options are given + if args.host: HOST = args.host + if args.port: PORT = args.port + if args.timeout: TIMEOUT = args.timeout + if args.encoding: ENCODING = args.encoding + if args.verbosity: VERBOSITY = args.verbosity + + # write pid file + pidf = open("pid", 'w') + pidf.write(str(os.getpid())) + pidf.close() + + print("aSRC Server\n"\ + "Server version: " + ServerVersion + "\n"\ + "Protocol version: " + ProtocolVersion + "\n\n"\ + "To stop the server, press Ctrl-C\n") + + try: + if VERBOSITY >= 1: print("Initializing server...") + # Create server + server = ThreadedTCPServer((HOST, PORT), ThreadedRequestHandler) + + if VERBOSITY >= 1: print("Starting server on", + server.server_address[0], "port", server.server_address[1], "...") + # Start a thread with the server -- that thread will then start one + # more thread for each request + ServerThread = threading.Thread(target = server.serve_forever) + + # Exit the server thread when the main thread terminates + ServerThread.daemon = True + ServerThread.start() + + + while True: + time.sleep(10) + + # exit if Ctrl-C is pressed + except KeyboardInterrupt: + print("\nGot Ctrl-C, shutting down server...") + + try: + server.shutdown() + os.remove("pid") + except: print("Failed to shutdown server correctly, "\ + "socket may be still in use or wasn't even started:", + sys.exc_info()) + #except: + # print("\nAn error occured:\n", sys.exc_info(), "\n") + + if VERBOSITY >= 3: input("Press Enter to continue\n") + return 0 if __name__ == '__main__': - - ServerVersion = "0.0.0" - ProtocolVersion = "0.2" - - - ############## - # SETTINGS # - ############## - - # IP or hostname (use 0.0.0.0 for all interfaces) and port, on which - # the server should listen - HOST = '127.0.0.1' - PORT = 24642 - - # Timeout of a connection in seconds - still doesn't work obviously... - TIMEOUT = 15 - - # Encoding to be used when communicating with a client - ENCODING = 'utf-8' - - # Dictionary of aliases. Use python syntax. You can use - # the variable send for text to send to the client. - # - # Shell commands can be executed with: - # import subprocess - # send = subprocess.check_output(["command", "arg", "somemorearg"]) - # - # You don't have to include sys, os, socket, socketserver, - # threading and time, through they are included already. - aliases = dict( - who = ''' + + ServerVersion = "0.0.0" + ProtocolVersion = "0.2" + + + ############## + # SETTINGS # + ############## + + # IP or hostname (use 0.0.0.0 for all interfaces) and port, on which + # the server should listen + HOST = '127.0.0.1' + PORT = 24642 + + # Timeout of a connection in seconds - still doesn't work obviously... + TIMEOUT = 15 + + # Encoding to be used when communicating with a client + ENCODING = 'utf-8' + + # Dictionary of aliases. Use python syntax. You can use + # the variable send for text to send to the client. + # + # Shell commands can be executed with: + # import subprocess + # send = subprocess.check_output(["command", "arg", "somemorearg"]) + # + # You don't have to include sys, os, socket, socketserver, + # threading and time, through they are included already. + aliases = dict( + who = ''' import subprocess send = subprocess.check_output(["whoami"]) ''', - where = ''' + where = ''' import subprocess send = subprocess.check_output(["pwd"]) ''', - uname = ''' + uname = ''' import os send = os.uname() ''', - date = ''' + date = ''' import subprocess send = subprocess.check_output(["date"]) ''', - ping_fanir = ''' + ping_fanir = ''' import subprocess send = subprocess.check_output(["ping", "-c 2", "fanir.de"]) ''') - - # This is sent to the client after the connection is established - MOTD = "Welcome! This is only a test server, for developing purposes.\n"\ - "Here (may) be more text..." - - # Verbosity of logging. - # Can be from 0 (only default output) to 3 (debug messages) - VERBOSITY = 3 - ############## - - - main() + + # This is sent to the client after the connection is established + MOTD = "Welcome! This is only a test server, for developing purposes.\n"\ + "Here (may) be more text..." + + # Verbosity of logging. + # Can be from 0 (only default output) to 3 (debug messages) + VERBOSITY = 3 + ############## + + + main() diff --git a/doc/protocol_reference.odt b/doc/protocol_reference.odt index f5be414d5b0c55fdd1bc66ddf97b682c564c24b0..fa01699aa3ed6bcccd2164483686267455a4e9aa 100644 GIT binary patch delta 13801 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 CiZ5vZ delta 14075 zcmZvD1yohv`YqiJ(p^%5ba!{FfTVOcN*%iUfV6ZY-5@C;-5?;1($XdImcM)7{r~S9 z?~LK#Z1>)4uf5j#<~Qg3)|p6!ol1wr)KG>;Ab^2Efq@wfPEEvA!UTV$cuZ_Ia1mf& zaBIzJ;n28sI0b~bUkY*YKoj6(5IOl(x%i;p;W%Kq>QUh_U@7=$sU0lbO@-cBo4T65 zbGLAP@y^M^(Os05^ChPMloNpoj*A~^fWQS0nuaDIP(d`^mIQG8yNnZ0g<+=~RMSG@ zXo`wx0%4~|FI5-OcWLcJlgQWC)`pSTkp+qdyv=Hg43BKDmz{_lJK5-5uF#a+lADbl zI(}vcV!YgT^*j)b6;5IOt$bchmZkOqCKe}{9?ph^G$xPXE~ZKO$B@yQcVrT#dB#DQ zIqq&4Dk+3Gc*WkX!|;bfiiP^eppjGqCr6c)(pN;${kNNag5`RR{(gRjs%wrPk(f$+ zJuA!YFAa1fT6E3%&BGN_3}2cG$?r6eRu_-PkE6Gi^_gn9 z;D>i%-RZDt?PZ3S_1e?*ec@#%9N)m=atCKc+Nv|ero-~6xQ%1ueVJ$)DY9A42kW2V z+eY*3;{IZ)S6=J&w>{Fvv(>g#QK(d7E}S6=o9Ih!j8?f`1S&X)FZXz3m2%VKs_dEH zTEFkcIV)68pOlZTmSL-MCh5iN^)sfxs&dCJ3e~6hb?VsSrsF^$TeZ;O;;VVjcn(+X ze|ozQDQ{WKVk=uA@`y6^-FSp8o75# z4P@4CIwdrk@tV5!yGo&s0Nc$|T^^qVCd*RBCq+R9cgX7jbquk78t&GnoPe{oK}PE1`HMcu zw<0gOoj5U@-rNRFZ2Ndekxi?|%uNQr#(}uu6cFS%H=KhtQ>!0t1zlGMCfz~yk!28$(b30F#tci5@vfFRuo6pH;sXSZW2cuV%Wjd zmj-!`>4)1E6X2OofOtm1Z7((TV}QwwE8I^f{uG_Gw*{;GhqtbNOViL62SqX?zmfW! zgxqdgC2^b&mQD;UqfBPMHw+8)g7#0pyY1m*zFWmS=Y%D~=`xj|{DjD7*2~2y^$&D6*Eh=i1s=TSi3t1pMGDY49Nlq8ROV z%x2oV@kR-n-bx{DWOsQ@#KT(O+hiY?&#Ej<7`)FEBWHp~l)4eF$32y!78%x_8b?E0Z zKT;|gLqwC5A)4lLl~z^vDz`2Ujf%P;J@&i6v?Icnl{Z>jmLAzN;8 z7xq={b%Tv$j~(=~u=jAGI+6a`A!>Wv-&yZR{lyMOnk0@k?`8syYjzY{n|~5BH{Pfo zXQSZpQLG-kj*9+GgC6dl%G6K!Gj->e6Cc+avthsbS}jyA^<2*wN1{*;ht8IpB*1xb z>igYKtgjAce)s~W%P#dra_lJm;}GX@|G1Z$J*XD!46sduXBLZiG2^Q2^^dmPxb(eq zI-4hHr`;X9$;O-0z5EFKA#7PU159@0xa7hw+)b0$Ypa`sUm7EQ)uQoz)u7|?mBnE! zYwC%Box-FCmgj10=%sEh=EOsPS=+UGob4*)ZN?LvhB7irQrl&O4I&H-106OD%)d|{ z1qJ0V>O%$5XdnW30Fd+ERs0+yR#AZC{`QLT+p&saoiKk*z1MXegFS3pBSSU4w3dN^ z$CK&P#$%G*cchq}xSkLJ`11tVvi8feu2&Td?eDLTf`8?s;wHIzYTC_{@yeu)Q4Grw zHRjx{k^E|O;&{4>!w#QiGz?!3luzTbA1Anvm&p9)I1BO7L`OJqWh*=6I>i01>zVo| zWUQf0anDiU)hz8?fx#P50ySIKv)m{ayYCE!B1~egOj)y@2%iXb=j+yI3-1z$bo~>m zIJeh5CI+L5HAGsHAG|fmSa-Zs-Gs8|OFjz`(ba$7b04ko!dm<^avSI@%{<5#seEBF zZ9kv+Q)M1Phep(2VgXHfvyK_TbVyoxf>z=l9iQtJxTJ|+GX%H=p-tx$RhQv1^PbGCrkS5*0y__{3m(>y<;%Tdf+aN~ta}|@3jCW+L6JtilZC;E*cyaZw2-X`^ z-rUuk#Go?FIDI@b^%rp;)v%^)Np7jv}VT|dW|?y6jjXOC~vSlp!<(>8Dk8}y_T>MVOHJ*YTrooXg_mK)4x^|{ZF z))JmJIbioq8K*?8L}q;TU-HF&jIl#}CqvvqN(iYMq@Z0)icn9%Y;{neiZ~}|xCp6K zEqRPt^k+QGfwg=p-W3nY!w$)(JcRM*6DC3PIiU^xLEyNC9_jS+UJ$4)=l;jqT3p( zk+>FN%3%q^WNn<~{k6*S2^Ahb0>KEmB~x?N^P9n1)0iS3gGhL*@?)2+au1Hq-2$2g zKVAzDPFFRPeg0hY_BXk5$!cvS`1To_wht0^%tK(U1Q*zHT8p1;PIf8xiw&z7mM9_C zsz=AE!7r5Ft1P(FCgdqeD=2P&dO(2gn`Qq)i3jpqX2Z#gDZnwJwh=kza}sf;Pj?I6580PjuyIHN>*HIL zFPoZsOH&JxNQB+71=O2+ZWVF-ru&s}<@@G3f56YzC)L^mIRk>KW@Aan^Ie|FB{EkIxd*+5PrPQo^ICLSh634){qs3P3G$5m1|Gmu!^ z#Hn8*)^jbrFub=uk!VfET{L?BHS|jjp@+QV&2C$u&eWc+dVX^4<6*b%c+}6l%EZjw zJeeWoriFpTVXZrxeow8RroV6LTQ)Tw3nt7JLih-mDSxF28#rN2_s>ZPufAfYgFKSb zX-HfQB76^=tU$WurasN4%*W&1fAu5C&0_0oomsShXMawu$z3bvbn!37GO=G8L}D+u ztt(d+u9Hx>kw4tvet-7{2|+Rh@9KJ1B6I91!^fz*lwvJQB4U{Z$0nx=*~yW2Q#29p z)tubB?0I$w1oG!$km@nQTnf5T#{=Q0C1`pY&~=&#=^!a4Ha~=5eN_LqBonR=?!6u6lNvlLc?VoC5jPL@(AJ5bBr#3t zeBWLkv+lcO=h#Ydir%se*8S_A{c`%s9|rdE1+~=OG!4(bcCd3#vWW&*RwY6xu|rhx z5WnHW7Z1&cQ2#)JqF1k2X(o~TU!Hri`9;u{P)lYCo=MZP;M#BcxD-Fm%Hkg)73TK2 z*6k*=voB=A2a#$|O6G2+ucKmBW3(gMOX~09!j3#BH*CHpT5eRPakBKB;De@j$Gx&h z`t8iVv38@y=@(AYSRB<~>ZAw}?L;3*tTqm1{y>*D2a*gn97ef;NUU>eqQ zY0Tm?S0;v$q%gx=!(~GS67mYvfijYtXr>t|k9V64a1bmXUi}oLcRr$Nu~)5 zdGoIBS6;sozIa9CXFm18ANRBF)%3TIBkOM`np)d0G~fo~pB5=F?Cgkb96vor zOwJ!EM=)f4)}2^SKCYj#e)u@}IJSXv1t%=8{hRzXY!+KuKHoe)!X45k<$+f|u~D1P zE$MZVrR-JG0VfifeM4Vw^FCzCD5}xcp7~36Q{*VeK*fMwX}j;K;a$z^sA1bfo;A~b zc1IRt&x@5g zU&WeHo3nLPz+KLo338=PnDE*L#M`^R^#~QLki&GYT;|)TG(;W0Ak%^*BO=Qzp(opa z?uSCF+s*8B3(fvS#+vqdMFu-k+1D+Xgr#7gXx-};_#ec=7hN2n@%wt4R}s6-l`f0n zm(@(JP}s1_81O1JFW*>6O@79COJ2q*^TURr^x*OsE4Gp7J!&yU7s3px(^~KKN*qUz zIbp|9us3S4VPg694W0@_vaMWmn{q|@B}YPpTIyPv2J*F5zm2Rbeipj#_%`eh?iAY3 zq$K<6?C!?Y(%BTFTPyX$h52i6v~wFW9?awAiIG*8YDbh<7U2GIqUX!i!r0lb>9M~I zM`xNV$MrzBof7tr`QAMgdy zs=`nAb3>@aA8)o&jr|3!#>t6@Qbm2P$c5a8zJ1&K;k9O1XZ~&b8}!AC7uUx>qI0N+ zA0Ph6$C0O}rpgP-$3rM7_#Mfya`>HA?=BC<#>VVsOISESV+k8aM9&(vDO6MKVQr1XelK-Th#0L?Jy@VZxN(#p~?_6hOUM|E>NRg zqDGzG-u~z3Sf;3`XyQOsk#cGr33nKHYPoKO*v)$I=B63JVw=aoRDnF*lN01m=J6-^ z0(++ILH;%0V2F58yVq|q$fK{$%V}I(+@qz&f}CAp%dw2PPCuVS=*N$8;RuL`dAE{w z8#_Cp`pDQ45b8uE8jY3y>4OJq*glG)K>(yJTroG%4N~G)T z>~wT=WME)uZEa2EFn*lLc{I1R)qnHm=4#n#d2vz1|6V{?SeStU@fHgUtL=;XfL#Ed zKe@0c8wUpmJNt2OD7v7aAPEV{#>U3Lz<`49!{tJ~)x^MRCchKy`HZ@_hl@*OM8wUY z_+#F=vQ-CC2ZTrblbBzd-=C}FAMMZS>CG)HXpoQOEiEmrtxJoFib6wWKkGM25P+xh zu-x9>VpEE|uXa(1A*bUG|qQ&@szPS3LHiq zZ#qlYM_E9`J~|8U>q5ry|b%pR7?yAklj+v zg1f7uc8J$+qwN6Bo}M1%k8FXKt&k_Nv=BoOEty;v!^NtZw)2&!{n1ekO--GiN2G^| zaxaX&csIIi4fOZ-Gu@Zu_)GneepUbta`M?4z$6aFSwz=E2*#z8%Myn?g2)5W_;oLW zs`Ph40*;O#-kSfP&*|yuIXP5u4yzr4)>hUKYZPwxPz?j{s(pJk(YL3x8ok)F_>ZY9 zjURjJ!-8Z<@sK=%U+hn>u6EYc;8fW`8C5l^J@#iMNqKcNGy+~c_5eH>k`ZKrrI#3^ zLH3mrygXQt_sI7Hkg!b9>QNL zfvWI)`&Vh=r%!R(P?A|fjCHQycJP?#y?4Iv@6unI!#Kf-U_x7 zc@j&s3K`Y7q4c~z74p%7sHmi|lx|?v6TAZp3+c;JOJ4BkOne>B7WM*@^~%!5qMU4+ zYZ~sG{q5P#(9|MgNNA`H#sITA=C`cZ?Kqf+YhA`h)%{<;cDDyDFt|GZfe?rr$by#y zOZz%i(&DBONRqml|1<`+u~1(XfAfVSt1Rf#-#F2`p!bge?jn z-~Xd{xUMPYeSxBmKVGbKq_F9{m?h>%x*CbYr6EyDHp^f`LJpT0^wdyP#K3~*$kz0` z<2+93g{cPXwrzqXF{F~X2U_<+U?9Xa+sZMR zHjpW!ocT)BvRN81B+^T1bWk7VSRxlS%Xrb5adluwjp&guhyxhqeY1Ovwo5 zFcqsr3FaZTg#xJPMFopH%XOGMhu2&C@E(?*XL=0x#C^;dx7mPQOSv$M;Ijn@JE zR8D2@S?%qGy8>z9<@<|W+y)mzfXHIxV`5?=t>4{+&0)5vk7tgUA0QA!cz9>q-|&fu zh@6>tcz8rad;wl4fSeNHsxek`ae5l4f#3mVsm6MW7KfIV^&py~69%H}`Fk}MPcDu; z^4a~(XKWUC>{MhPZo_kkJ0C0UF`A!NT;Lqkp7Jvyo~s9x$VjVk{5c-^HPa@QRQ&)oYC1h*N- z7iao)rx$)+7Z2BKGX~=%+?JEk1-cclHk@&pXzLW_UKmJ`&^=D^x z8x>UP=Nh{?Q3~j{cay6XE(+-zzk8F6GHp8&XZ_XnEx#dRWCvWLL#ZjLpp=w25ReKT zmYYBV|Iz8!{^9&5#XnSzlbd^FY^<@d@dcPqIB_bG_a?TsQJ-sTUB)tanO)^c&!o9c zSKGbRNiV^djI=Zj9bEYb9iiltEx-r>)@y2Nf(3wyfq|g8zfkSu5``hzR zpFUZO+s>9s(rI2FEr;)Wd3j-DVuE~EnVn5hDxs_Zl654lS0Rl!4}Nh)MFr1(xMgn# zNU!n_yQs-0@DRU5LQTPU12H}78M}CbCf$JKp+V5mHFtXD=(erEkS}S952eaIbD34& zkxD)9D}5v`-yy&*QVpSsf&ANGJQZC@ zZf^I~6fPyhii)8zO937r$~@xRS4Yb|*aGo}ZSIO{YGJ~zAWImwdjhJB-dUKE@(ePT z*1qb2>->xT1+ zHd(}bmi6saQc}`DELllW(H!Kn0ns?KFV+Pcn2lh%q)(sJw71QORN;y6@$qqRVBXy@ z`TP5y=qIG7q%hnBG9nwaGxY*4bHZxPINoObq zFL$dU@Fav_+ZTqZS*CDvcXzzpjE%+IFxqIh(2ecQjnswEE+r)u1Br>r;Bx>t5_P}0 z_~xcwff`!8pFcbhI6pscHJ%0g91b2Hn_M8EH##cn1RA5c4)QJlCT|3Vk=8J1tqgzUduv_dr+tfy#3DoE;}E&$aCo_YTD&i9m6XupiayY~`&P%K zhU57+IIS5KIbO*UNr+r!C zXYFnlPp)!=_i@xtT$d{wL`qpTld-4-YHdhg9oB<`#NQt)*K#V*z_!ZhGNY7-|$Ma(Z!5XknvQ z*U70-<)pjsMTUroc(F-dPESWy(9)8|aFB_xb2mRW7HgCqeH4lReApl)K~pwQ#6Nr9 zMtaNC+BzZ!lZ>wr+ckzCb$Dw*T1u+TeXq`Pj1)}$g#aolDo8oxO^;!cA0YQavQ^DC zGd}@rS<7Z+XKy4sFW!+M?VKJoM14ud1Xul(TEI*puHD&76P|DkV2uoow@?e6Na^mRUoKnXuU?0SSv|t@_p~e0NRFQQ*Gv8>Mwr(4my!X zsF|v;*5X3P$47WCQ2^Hl^x)#ul*?4UED&r!n}=;nw!^*3Qx;^vmK!wK;H0IP>@HyiPX61D%3AJHNj|i znf8U@e9_=MQL|mB^839iN*qtjNlQofZZwVach{5H)#Ls71mN{2{1oKm>s3+k)rRdz zJ9QQ#gr%7c4LmM~fHjzYOicx)kC}EJsH|j*FlRx= zngr@1w>unz1VFO?<-V@K2vCd_uRaHzM@P%30iNT+$%GTCEl7>_`FNa~DTb=AKn4zr z`BPnVG`c&R3qis(COu{bGJ?OPcNeUU#vnt$=WY%7%m%LXKZ9%2?`zK_PV7T+1IsIr0 zb=}!nw_#A)OpNg5;Oi=W$`bh5*>}e*CI+ES0$bN{dUWeZy4)5}(Cp zo^tq9oL2BOKBG!50*Uq^NdTma%Z6%i(b1$k0M=aYxl~3mF>WY~Y6cHYCQu7X@>Z9- zQvg(Q2F#{%*|M?=x!ASdMA=!-mg0KxkWTL0x6tNs4z!KJYFeOCrF=ADo~Z0l*=sFy zQf(kw{`e_kcq7nY=`ZaK#`8a1{jxki-vkJh6mEhPv$mduwniL8p|oLENks)?>FO8z zCQUX%?I^m{rB&GKR?e;EvlzFqaB@<2(=#OsmFv5n{WOAx zWJZX}f*FPS`uGrXsN$yAV?>U)>HYqFcaiJ{)7a=JhE?S_c#J|cg6Z&sSNw%hDe4mkFf25 zZ^2-dFskra`sqV~)K;lGXKKooIX;i8JVW{jn&mA04bEB_7RFlGK}kbHz3R!h3)LWBlCp8dMv*>pAgRx z@?Z(g494f=gdl*r3ON()kBW1CEWfZMeZ5xKqD8Ib z56;dt7raFM#nJq)mvHw1jN@0B5q>sCBuoVDt*8+CCBUXZMmb8iFk z=W}(qx6*okx;0p|@sm_@olEnlmW~LM4CRC&EtCeE;Xc;`r55r75F%jX88q6aWM;DF zcQc1c%cN_sw4z{ky+1Y6(7@rrLTtA~4%Ltl@yr%zElRixAO&I^;Q1%O#aUflrCl_nV+w)W)ZMS{q-8>=Q}~KEsbp?r zW8>^Cfu$c-3>?JGGi&D2o16E<0qw|GMx-m8Zl$CbSENx3e zObHUyN&5R3d38xN!t(cb7kksYIGSvTp%9fUfke;9kbz$w4TLNnU&EZEc!NYh!=6V= zn#CZirBKiFzUvTR+0Kd5@QB6n#3Zw^Zc&+yAat0iaNGU-h;3VR-BrZ z6`i+Ss~-7npvi}`ZB$H)060icTv6Z5%uEk_k_bT88aCZvHJL#nA)%lGAQNO!%gV}t zmhRtJM^i(uVmMwS>x(!>NU#8LbN z7DJ*kD?K(vv`i|yp#pv&Espl~qL^P8nh5^DleE>AlP)Bg%t8qg51?LK>Q4n`QGYWr z&4)rkQrLq{X!VuC651+(G*F6vqcbr*J@Tn^G!?f6j^&c)Xz6y&SHLbMIH^1+O-3D; zg2KVxUPZY~8;Z5IdA$a?K0T$Od1qU|ypkQEhcphZ{U4%l9fkiHm09LjOELuoySgfFbpl+f1_;^DH(WtiVPZ#8zP6*3eUny98-pOz zK0G`?laf|eRsae5wXqTS5#I0{FfFeSzeCP}>CQ+`@BDOTDY0?=V9@NCcMRsEzP?`b zU>&&)?>)^r!k3ZF$DJ|Yd&iJ)BVhnX7o;g!XAh5}st~bGVF7{C;eF$T-GyqZuAEXS z(8Y?^)$$-Q4QY|lf0V;9@VXx^a@yPUDBZ1){v)s;0dYUic1E1l zY^sVu>OY}lVNu$T&V~FH32YmU3cno8jAg_DBe7;d!loq0#f2TDrKkToG!$X!AEb>3 z489^|qKt%Zz-YmW3gdv|NFm3K{gCPIXN>Vf0#!T=o2ttDiqis!q28RD=4Qz6FV|l& z)RPslqE2KBw~EUl=N+oLh(b4FC5h}DG3r}BndROS%R0Kwg_0owK{*j-awn z1xXA1JI_=u$x}KynX668f0f=}s(wJ!_LJMGb{gKEv~sQ(|C?z~d?w1HQz=LaYaViE zvV=U)I?IcSEHe2Vn5fhSe&s;eN3FZ3(Lc7D^`k*<>c_{&dDPURfSs>lj_U5=>nl=Z zOvvHE85O7v$|qyl!msJ5USkm%>DC&QQWM zwGuS$a<;Ab_6^{yxyvpbEmF1a&sJ_hA_Osr8L!}t4)lU_IF{e>+qWq}Xs7T(3|w4z zk%x!&_B7hM`;mIdDM)Go2q(UPV53M?0&M&_ny#m(2Soq(HV@ViPD%!*pkD?hY83a+ zPMkGiLAhm7H?e*41-mh%Qv^^S5UqYU8{zNSG%l%ys&KO2G}=C^0?YO77GVIe!n*?R z|GHEPyZLg=zuJFyYOjPjt#*(M=63>R`(tHg66GHNI$WwT?E`7O&Ur%$9v(i!TB)eo zaT1xzH}~!xzq$>neN6Q89*!@Fe*O>IQzJ>^R5GOskj6+9SnqgR%xB>FRPL@(3)rA+ zYlg&Nn%lgs!TfVDdLhARuE@wxB}F3i0=>X?!{dNxfDHR@*8XcC5}a*;VFe=O^86gU zJ+VXA-99TP3R)26eityZL0PQ9>+${;hy{V|=^|w?*9|H{?oVHQu7NG2j-L$KcrKIM z+A5g-#&(A27@$p^*4aWvssy#-v7$> z0-We|z2#VGDU<1W*VBX3Y^mmCMYH1%(w8O@CMN4Zn%M-XJUu>OQwW6^-UwO@Cj)7g zpr@oX49cGx;~ZW0br8^XV6OxVwSD<8;Fgy_1?J}4w{M`}bz6J;*7KpjccFTqv`3x1)L;WYo_9O7 zW>xOGx8?e_(h?b~&umAzN*|!3=8Se$9h5cxrb8PkUB*^AHYa~B zZ4vyt#wR)dhU-glP~jSi2LQJQJUtL9X2L#K_9#ohM2#imk27Nd?kd0aB(;yvAALxp z?bOin^t2WkS?2w{FEOa>VO)W7*dijlkWBOSK&b$jVW21hOA+%r&Pq=waqv1`xn1@7 zP4fh*d%Rp+8C(`hU_^ru(SdsI>+9=*dH%cv7|8BNOT2()v9XN;Y_e1UlqHxI2t)yd zfwnKAa){v7fK8YVNl$XjL5m_S-uT5cU6AR1l%e)?*|Q&Y7-F#{I}lqWxY_yAg} zDbp-K^2`(LA$$=Ih{2fq&?GC?7!8D5k0+Q?_#qb+JUz=O$QbNbZVw zN*K-v8%4R{HR*r~mLJjq(Z5XZlWXt=yc%RQoqPMWnVpRdYMVr!bta8CAK(1sq%#<~ z0=ZZgHnu{&WLCs#E8ixutxG>htLskGdU#IG8W_moZDbrODsfQ121#G<%^Q^r9>wo_ z#3_h7zs0SSsO{ZmnI@*cex(PBe{rz|$d0bZJ3G*BiqT(lFoBBas14;0#Ldf#W5N|^ zOzU^n-;m`}q(e8+jS;+ezU|NT>!5Zl-B5pVMZMfNV?nH*5RZ+H#(!k?O-xF{b8`C4 z^#T|hz~08e$KTr8qT|xm(zfMr&ziTcz8(xLOcA&L{S6R- z!L+~~1Y=qwi8>7V9dOE$2mb(c#u9KOQmww1X_q*4Jv4!6V`pavrTf4r$z^DII_fHr z{w=`b_k;5bbG(Qav6ho2E>OpHW8OO_*TjIG=fDuG@h_7r<#~`QC>?3Qz{2u>dbp;e zqeDkSBjtC**viVv0u|S_jt?^n3k$QevvYI0-+3V~jo?9d;o#t;q@_o;4H3Y9L%d`3Ag~p4OR(=XX7v4yywz6pu;^+EL*_zetYu;1ZSGcz;M z<#}mndRAAB_ENZwkU_&5GnAB+J9?njY*0A0*kC;c7r8f6QZcI*Q&Lh=hi(G-R~!Wn zTD_(_xv>w6>-o1h0muWKJpuv(iFVtV33fKNEFPO_b@2xTL_2G1Vp38xT=YgWJ39j% zoe*j2m_z|kCyxP)A5>b^qj$f4{n`NvdegN_JTYXU5jhPtXTXyXzuPTv>bzxSVnQj} zkT5njX2EBGO#Tr%!c$RIJ)HrL-~#Z0%9g`#kfdqEg}jbCyf62G9TTOw#3M##FpE%* zhN|!#hy}2H!nY>~5$s=(^;m6n8w6QxWkrOA1uaQHM5F_Z**XGVRaF(}PGa2LYO|B^ zn>TO35ZW|c11~~j28<&F)MJ?NsHoy0=n-*o1AziW_8LFq#UD}pCz*MaTAVj}C-bC% zh6TK^_3Bvy8^3>d0fGv=0ASw&o;Qo|xCScr zxrm9{+S-5RS&pC^5|RlX=_g>Rf;vHfkac+ByG9#gepg`01?50W-|Od~IY@v9fwJZh z3^MS`3e1xu;l6zNvPVG5V8SsTs@%`6UmphQ)I;%kwxzQpv^Mb*$1^3^I|}eH8lh%P zd~wf$>({)I=BNg3k&%&=t(xqClUOuGs);pL&4N)ndZt9oXPcSxc4xt!k#80f{tmcdL43f=-C3l=Ui zHYEa?1apcvr>91FON#(2>&WWrBUnlxOtjwP$GiqNI=|kM9k9YC;o1g7x1p`}VkhLy zIRjV+xw$5wqBpl9IH`VeH}vo5B!8e47ZYY=M0$v>uCA`bhj6kG2~BdGZPnAfQBqch zJY2rE-|(epV7T0yK{gml2RnhnLPIYPzt0Q|6vH)lzYm=Z^iQP9Ia*(b;oIKX$$M6& zSI_uXQ-QcNC5}QEY*NtE*Ed6tV*27gP!S4n0;6LtfZ?-@B9&p@s|a?p7Cve5)8Wf# zBR>v{hqF2jwBC5zD!B4zEe=-D2Yzm_NePF3;|YdxGH{aRdRZ0*d=zEXWU8c0g8qBg zxwe4H-(LjP=L?9y{`1qI4ME<2{*nj@{ri{(>Z6E({=a^p1lu-f?Q2+T-DeLsF9#G12|M%~ophoh{df-~A z|Jgkc1B3DRo&NI)0l$-Svv7B}akO${fA3(gp$rR007C%t@6Gj6|Jh;&c9^06=dQnB zol!(Hs3txs+yC2W+qu~3GjJgx`1jx4Q4oZhD3Jd1o_-2s zaH)dOjDH`hD3Za=3qel=DKY=m!+-B|gFb=lu!N!HiZA}T?eBHU!cZGUrvDrU3qx!F zeYgV7whKdV6&e5O`Ty=L`TstEITePAE3y33#NT^ZMWB&NjQ=?_6@gAD{ZA8c|GxG4 ze>IUR0<9HhhKea;{BxhGGMUh^2pDbm5B3)S-?2{Ul{$F=3j>n}=H&12{Ld#(4w|q0 L90^z9?|=OtG`nWO diff --git a/include/__init__.py b/include/__init__.py index 174e139..6ff74a1 100644 --- a/include/__init__.py +++ b/include/__init__.py @@ -1,2 +1,2 @@ from .argparser import argparser -from .content import content +from .comm import comm diff --git a/include/argparser.py b/include/argparser.py index 517ebf6..bf66b38 100644 --- a/include/argparser.py +++ b/include/argparser.py @@ -1,78 +1,77 @@ # includes/argparser.py # -# module version: 1.0.20130424 +# module version: 1.0.20130425 # class argparser: - - def parse(program_version, protocol_version): - import argparse - - parser = argparse.ArgumentParser( - description = "The server side of the "\ - "aliased server remote control", - add_help = False) - - - parser.add_argument( - "--help", - action = "help", - help = "show this help message and exit") - - parser.add_argument( - "--version", - action = "version", - version = "Server version: " + program_version +\ - " / Protocol version: " + protocol_version) - - grp_pid_file_failure = parser.add_mutually_exclusive_group() - grp_pid_file_failure.add_argument( - "-n", - "--delete-pid-file", - action = "store_true", - help = "deletes the pid file and starts the server") - - grp_pid_file_failure.add_argument( - "-m", - "--allow-multiple-instances", - action = "store_true", - help = "ignores the pid file and starts the server. "\ - "Will not create another pid file.") - - parser.add_argument( - "-v", - "--verbosity", - type = int, - choices = range(0, 4), - # default = -1, - help = "increase output verbosity. Can be from 0 "\ - "(only default output) to 3 (debug messages).") - - parser.add_argument( - "-h", - "--host", - # default = -1, - help = "IP or hostname (use 0.0.0.0 for all interfaces) on which "\ - "the server should listen") - - parser.add_argument( - "-p", - "--port", - # default = -1, - help = "the port on which the server should listen") - - parser.add_argument( - "-t", - "--timeout", - # default = -1, - help = "timeout of a connection in seconds - still "\ - "doesn't work obviously...") - - parser.add_argument( - "-e", - "--encoding", - # default = -1, - help = "encoding to be used when communicating with clients") - - return parser.parse_args() + + def parse(program_version, protocol_version): + """ + Parses comand line arguments + """ + + import argparse + + parser = argparse.ArgumentParser( + description = "The server side of the "\ + "aliased server remote control", + add_help = False) + + + parser.add_argument( + "--help", + action = "help", + help = "show this help message and exit") + + parser.add_argument( + "--version", + action = "version", + version = "Server version: " + program_version +\ + " / Protocol version: " + protocol_version) + + grp_pid_file_failure = parser.add_mutually_exclusive_group() + grp_pid_file_failure.add_argument( + "-n", + "--delete-pid-file", + action = "store_true", + help = "deletes the pid file and starts the server") + + grp_pid_file_failure.add_argument( + "-m", + "--allow-multiple-instances", + action = "store_true", + help = "ignores the pid file and starts the server. "\ + "Will not create another pid file.") + + parser.add_argument( + "-v", + "--verbosity", + type = int, + choices = range(0, 4), + help = "increase output verbosity. Can be from 0 "\ + "(only default output) to 3 (debug messages).") + + parser.add_argument( + "-h", + "--host", + help = "IP or hostname (use 0.0.0.0 for all interfaces) on which "\ + "the server should listen") + + parser.add_argument( + "-p", + "--port", + help = "the port on which the server should listen") + + parser.add_argument( + "-t", + "--timeout", + help = "timeout of a connection in seconds - still "\ + "doesn't work obviously...") + + parser.add_argument( + "-e", + "--encoding", + help = "encoding to be used when communicating with clients") + + return parser.parse_args() diff --git a/include/content.py b/include/comm.py similarity index 64% rename from include/content.py rename to include/comm.py index 79a4545..24b1479 100644 --- a/include/content.py +++ b/include/comm.py @@ -1,18 +1,59 @@ -# includes/content.py +# includes/comm.py # -# module version: 0.0.20130424 +# module version: 0.0.20130426 # -class content: +import statuscodes + + +class comm: - # handler the content - def handler(client_address, data, aliases, server_version, protocol_version, verbosity): - ret = "" + aliases = dict() + server_version = "" + protocol_version = "" + verbosity = 0 + + # initializes global settings + def init(ServerVersion, ProtocolVersion, Verbosity, Aliases): - ret = ret +\ + aliases = Aliases + server_version = ServerVersion + protocol_version = ProtocolVersion + verbosity = Verbosity + + def header(statuscode, AdditionalHeaderLines = ""): + """ + returns the header + """ + + ret =\ "{BEGIN}\n"\ - "asrcp" + protocol_version + "\n" + "asrcp" + protocol_version + "\n"\ + statuscode + " " + statuscodes.description[statuscodes] + "\n"\ + "ServerVersion:" + server_version + "\n" + if AdditionalHeaderLines != "": ret += AdditionalHeaderLines + "\n" + ret += "\n\n" + + return ret + + # returns the motd + def motd(motd): + """ + builds and returns a motd package + """ + + ret = motd + + return ret + + # handles the content + def command(client_address, data): + """ + processes a command + """ + + ret = "" # Look if the received message is an # valid alias or a predefined command diff --git a/include/statuscodes.py b/include/statuscodes.py new file mode 100644 index 0000000..b106ffc --- /dev/null +++ b/include/statuscodes.py @@ -0,0 +1,37 @@ +class statuscodes: + description = dict( + # 000 - 400 server side + # 000 information + 001 = "OK", + 002 = "Version", + 003 = "MOTD", + # 100 authentication and maintenance + 101 = "Challenge", + 102 = "Success", + 103 = "Failure", + 104 = "To Many Tries", + # 200 command + 201 = "Valid", + 202 = "Valid Service Command", + 203 = "Invalid", + 204 = "Failure", + 205 = "Continue", + # 300 server + 301 = "Unhandled Exception", + 302 = "Shutting Down", + 303 = "Restarting", + 304 = "Encoding Error", + 305 = "SSL Error", + # 500 - 900 client side + # 500 information + 501 = "OK", + 502 = "Version", + # 600 authentication and maintenance + 601 = "Response", + 602 = "Failure", + # 700 command + 701 = "Reqiuest", + 702 = "Cancel", + # 800 client + 801 = "SSL Error" + )