#!/usr/local/bin/python """ ptping.py -- Python Threaded Ping. A multithreaded pinger written in Python. ptping takes as its arguments a file containing a list of IPs (one per line), as well as an optional argument for the number of concurrent threads to spawn. For a large list of addresses, this script is potentially close to n times faster than sequential pinging, where n is the number of concurrent threads (with diminishing returns for very large values of n, of course). -Dan Sneddon Creative Commons Attribution-NonCommercial 3.0 Unported License """ import logging import getopt import sys import time import re import os import socket from threading import Thread pingcmd = "ping -q -c2 " def parseArgs(): """parses the system arguments to a consistent argument set""" options = { 'help': 0, 'verbose': 0, 'infile': '', 'threads': 10, } try: opts, args = getopt.getopt( sys.argv[1:], "hvi:t:", ["help", "verbose", "infile",\ "threads"]) for o, a in opts: if o in ( '-h', '--help' ): options['help'] = 1 elif o in ( '-v', '--verbose' ): options['verbose'] = 1 elif o in ( '-i', '--infile' ): options['infile'] = a elif o in ( '-t', '--threads' ): options['threads'] = int(a) else: assert False, 'unhandled option' + str(o) except getopt.GetoptError, e: print str(e) sys.exit(2) return options def printUsage(): """print usage options""" # Add options to shortoptions and optionsdesc for --help printout shortoptions = { 'h':'help', 'v':'verbose', 'i':'infile=', 't':'threads=', } optionsdesc = { 'h':'Show usage and exit', 'v':'Be verbose (print debugging messages)', 'i':'File with list of IPs (-i) *Required', 't':'Number of threads to spawn (-t)' } print 'Usage: ptping [options...]' for k in shortoptions.keys(): print '[-'+k+']', if shortoptions[k] != '': print '| [--'+shortoptions[k]+']', print ' '+optionsdesc[k] def read_infile_values(): infile = None if options['infile']: infile = open(options['infile'].rstrip(), 'r') else: print "ptping: no input file specified" printUsage() sys.exit(2) filetext = infile.read() infile.close() alllines = filetext.splitlines(0) lines = [] for line in alllines: if line: lines.append(line) return lines def getnameip(host): ip = socket.gethostbyname( host ) result = None try: hosttuple = socket.gethostbyaddr( ip ) result = [ hosttuple[0], hosttuple[2][0] ] except: logging.debug("Hostname could not be resolved.") return result class pinger(Thread): def __init__ (self,host): Thread.__init__(self) self.host = host self.status = -1 def run(self): pingresult = os.popen(pingcmd+self.host,"r") #print pingresult.readline() #print "started" while 1: line = pingresult.readline() if not line: break rc = re.compile(r"(\d) received") received = re.findall(rc,line) if received: #print "status is: "+str(received[0]) self.status = int(received[0]) # main() if __name__ == "__main__": """parse arguments""" # If no parameters supplied, print usage and exit if len(sys.argv[1:]): options = parseArgs() else: printUsage() sys.exit(2) # remove duplicates and sort list hostlist = dict.fromkeys(read_infile_values()).keys() hostlist.sort() report = ("No response","Partial Response","Alive") pinglist = [] for host in hostlist: pingit = pinger(host) pinglist.append(pingit) pingit.start() # create more threads? waitfor = 0 if len(pinglist) > options['threads']: waitfor = 1 if host == hostlist[len(hostlist) - 1]: waitfor = len(pinglist) # reap finished threads if waitfor == 1: i = 0 while i < len(pinglist): p = pinglist[i] if p.status > -1: p.join(10.0) hostinfo = getnameip( p.host ) if hostinfo != None: print'"%s","%s","%s"' % (hostinfo[1], hostinfo[0], report[p.status]) else: print'"%s","%s","%s"' % (p.host, "", report[p.status]) del pinglist[i] waitfor -= 1 else: i += 1 # reap any threads necessary for reap in range(waitfor): pingle = pinglist[0] #print pingle pinglist = pinglist[1:] #print "Waiting for ",pingle.host pingle.join(10.0) hostinfo = getnameip( pingle.host ) if hostinfo != None: print'"%s","%s","%s"' % (hostinfo[1], hostinfo[0], report[pingle.status]) else: print'"%s","%s","%s"' % (pingle.host, "", report[pingle.status]) #print "'"+pingle.host+"','"+report[pingle.status]+"'" sys.exit(0)