#!/usr/bin/python # Server program from socket import * from datetime import datetime import os import time version='0.1.0' # # MISSING FEATURES # # FEA1 : Multiple files and client handling # FEA2 : md5 file identification based # FEA3 : REGISTER checks md5 and date # FEA4 : CONFIGURATION based server # FEA5 : Defining and implementing command line option # FEA6 : Objectify the application # FEA7 : Support links and directory # FEA8 : Support bandwitdh limitation # FEA9 : Limit listening interface # FEA10 : Configuration for log cleaner # FEA11 : Referer master only # FEA12 : rigths handling # FEA13 : Secure udp stream # FEA14 : Plugable file treatment # FEA15 : temporary file write during data phase and move when committed # FEA16 : Support for small changes only such as rigths or mtime # FEA17 : Recursively files and directories stucture # FEA18 : Coupling with client to be able to have cluster based synchronisation # Set the socket parameters host = '' port = 12000 buf = 1024 messageTimeout=5 addr = (host,port) ip=gethostbyaddr(gethostname())[2][0] #misc parameter rootDir="/tmp" verbose=1 filesData={} nbReq=0 retries=0 def getNowEpoch(): return str(time.mktime(datetime.now().timetuple())).split('.')[0] def handleError( request ): if verbose: print "*** ERROR;%s;%s;error for request '%s'" % (ip, getNowEpoch(), request[0]) return "" def addData( fileName, index, data): global retries if not int(index)%2: if verbose: print "*** Stop even index...." retries+=1 if retries<2: return global filesData global nbReq filesData[int(index)]=data nbReq+=1 def handleData ( request ) : type, index, fileName, data = request.split(';', 3) addData(fileName, index, data) return "" def handleRegister( request ): global nbReq global filesData global retries type, fileName, size, lastModified = request.split(';') localFileStatus="KO" if os.path.exists("%s/%s" % (rootDir, fileName)): localFileStatus="OK" elif verbose: print "*** %s/%s doesn't exists" % (rootDir, fileName) if verbose:print "- Request : %s \n- FileName: %s\n- Size: %s\n- LastModified:%s" % ( type, fileName, size, lastModified ) if localFileStatus == "KO" : nbReq=0 filesData={} retries=0 return "ACK_REG;%s;%s;%s;%s" % (ip, getNowEpoch(), fileName, localFileStatus) def getFileDataSize(): size=0 global filesData for data in filesData.values(): size+=len(data) return size def handleCheck( request ): global nbReq type, fileName, size, lastModified, nbCheckReq = request.split(';') localSize = getFileDataSize() localStatus="OK" print "*** Checking file '%s' sizes:\n- client size : %d\n- server side : %d" % (fileName, int(size), localSize) print "*** Checking file '%s' packet numbers:\n- client : %d\n- server : %d" % (fileName, int(nbCheckReq), nbReq) if int(nbCheckReq) != nbReq or int(size) != localSize: localStatus="KO" listMissing=[] for i in range(0, int(nbCheckReq)) : if not filesData.has_key(i): if verbose: print "*** %d items is missing" % i listMissing.append(str(i)) else: if verbose: print "*** %d items is OK" % i if verbose: print "*** Missing list : %s" % listMissing return "ACK_CHECK;%s;%s;%s;%s;%s" % (ip, getNowEpoch(), fileName, localStatus, ";".join(listMissing)) return "ACK_CHECK;%s;%s;%s;%s" % (ip, getNowEpoch(), fileName, localStatus) def commitData2File(fileName, size, lastModified, filesData): fullPath="%s/%s" % (rootDir,fileName) f = open(fullPath, 'w') try: for chunck in filesData.keys(): f.write(filesData[chunck]) finally: f.close() os.utime(fullPath, (time.time(),int(lastModified))) statInfo=os.stat(fullPath) if verbose: print "*** SIZE: \n\t- Remote size : %d\n\t- Local Size : %d"% ( int(size), statInfo.st_size) def handleCommit( request ) : type, fileName, size, lastModified = request.split(';') if verbose: print "*** Cool a COMMIT for '%s' :)" % fileName localStatus="OK" if int(size) != getFileDataSize(): localStatus="KO" else : commitData2File(fileName, size, lastModified, filesData) return "ACK_COMMIT;%s;%s;%s;%s" % (ip, getNowEpoch(), fileName, localStatus) def handleRequest( request ): handlers = { "REGISTER": handleRegister, "DATA": handleData, "CHECK": handleCheck, "COMMIT":handleCommit } if verbose: print "*** HANDLING '%s' request" % request.split(';', 1)[0] return handlers.get(request.split(';', 1)[0], handleError)(request) # Create socket and bind to address UDPSock = socket(AF_INET,SOCK_DGRAM) UDPSock.bind(addr) while 1: data,addr = UDPSock.recvfrom(buf) if not data: print "*** No client" break else: if verbose:print "*** Received message '", data[0:60],"...'" returnMess=handleRequest(data) if returnMess: UDPSock.sendto( returnMess , addr) if verbose:print "*** Return message : "+ returnMess else: if verbose:print "*** No returned data" # Close socket UDPSock.close()