#!/opt/Python-2.4/bin/python """ DistMon server: Calculate pings to faraway machines, and return them to a web server This software is primarily for demonstration purposes in the planetlab tutorial , and to help me learn python. There is probably far more appropriate software out there for this job. When started, distmon registers with a home server, giving its current measuremnts, and receives a list of IP addresses corresponding to ther distmon servers it should ping. It inserts these addresses into its dictionary (if needed) and starts pinging the entries. It then loops forever. This code leans heavily on the Heartbeat example in the python cookbook DistMon.py [timeout [udpport]] """ UDPPORT = 43278 TIMEOUT = 5.0 CYCLETIME = 10 myurl = "http://139.184.48.49/cgi-bin/DistMonCGI.py" import urllib from socket import socket, gethostbyname, gethostname, AF_INET, SOCK_DGRAM,timeout from time import time, ctime, sleep from threading import Thread, Event import sys import marshal import pickle class PingDict: "Ping entry dictionary" def __init__(self): self.dict = {} def __repr__(self): list = '' for key in self.dict.keys(): list = "%sIP address: %s - Last Time: %s Total: %d Rtt: %f Dev: %f Loss: %d Heard: %s\n" % (list, key, ctime(self.dict[key]["entered"]),self.dict[key]["total"],self.dict[key]["rtt"],self.dict[key]["deviation"],self.dict[key]["lost"],ctime(self.dict[key]["received"])) return list def merge(self, key, entry): self.dict[key]["total"] = self.dict[key]["total"] + 1 if entry > 0: self.dict[key]["rtt"] = 0.9 * self.dict[key]["rtt"] + 0.1 * entry self.dict[key]["deviation"] = 0.9 * self.dict[key]["deviation"] + 0.1 * abs(self.dict[key]["rtt"] - entry) self.dict[key]["received"] = time() else: self.dict[key]["lost"] = self.dict[key]["lost"] + 1 self.dict[key]["entered"] = time() def insert(self,key): self.dict.setdefault(key,{"entered":time(),"total":0,"rtt":0,"deviation":0,"lost":0,"received":0}) def keys(self): return self.dict.keys() class UDPPing: "Open up a socket on which to send pings out" def __init__(self): self.sock = socket(AF_INET, SOCK_DGRAM) self.sock.settimeout(TIMEOUT) def ping(self,addr): addr = gethostbyname(addr) self.sock.sendto(marshal.dumps(time()),(addr, UDPPORT)) try: while True: data, returnAddr = self.sock.recvfrom(64) if returnAddr[0] == addr: break return time() - marshal.loads(data) except timeout,msg: return 0 class UDPPingServer(Thread): "Receive UDP packets then send them back out again" def __init__(self,goOnEvent,port): Thread.__init__(self) self.goOnEvent = goOnEvent self.port = port self.sock = socket(AF_INET, SOCK_DGRAM) self.sock.bind(('',port)) self.sock.settimeout(TIMEOUT) def run(self): while self.goOnEvent.isSet(): try: data, addr = self.sock.recvfrom(64) self.sock.sendto(data,addr) except timeout,msg: pass def main(): pingGoOnEvent = Event() pingGoOnEvent.set() server = UDPPingServer(pingGoOnEvent,UDPPORT) server.start() pinger = UDPPing() dict = PingDict() dict.insert(gethostbyname(gethostname())) try: while True: if __debug__: print `dict` for addr in dict.keys(): dict.merge(addr,pinger.ping(addr)) f = urllib.urlopen(myurl,urllib.urlencode({'IPADDR':gethostbyname(gethostname()),'RESULTS':pickle.dumps(dict.dict)})) # print f.read() for newaddr in pickle.loads(f.read()): dict.insert(gethostbyname(newaddr)) sleep(CYCLETIME) except KeyboardInterrupt: print "Exiting" pingGoOnEvent.clear() server.join() if __name__ == '__main__': main()