diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..73f11b6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.py[co]
+*~
+*.egg-info
+/dist
+/build
+.pydevproject
+/.settings
+/.venv*
+/.idea
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..b1e1167
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,18 @@
+AUTHORS / CONTRIBUTORS (alphabetic order):
+
+ * Cowles, Matthew Dixon -- ftp://ftp.visi.com/users/mdc/ping.py
+ * Diemer, Jens -- http://www.jensdiemer.de
+ * Falatic, Martin -- http://www.falatic.com
+ * Hallman, Chris -- http://cdhallman.blogspot.com
+ * Harvey, Dan -- https://github.com/danharvey
+ * incidence -- https://github.com/incidence
+ * jcborras -- https://github.com/jcborras
+ * Motl, Andreas -- https://github.com/amotl
+ * Notaras, George -- http://www.g-loaded.eu
+ * Poincheval, Jerome
+ * Sarkhel, Kunal -- https://github.com/techwizrd
+ * Stauffer, Samuel
+ * Tibold, Marko -- https://github.com/markotibold
+ * Toews, Ben --- http://btoe.ws
+ * Zach Ware
+ * zed -- https://github.com/zed
diff --git a/CHANGES.rst b/CHANGES.rst
new file mode 100644
index 0000000..9efc285
--- /dev/null
+++ b/CHANGES.rst
@@ -0,0 +1,39 @@
+***************
+gping changelog
+***************
+
+In progress
+===========
+
+2016-11-21 0.2
+==============
+- Be graceful to hostname resolution failures
+- Record all failures (hostname resolution and timeouts) in ``self.failures``
+- Improve console output formatting
+- Add shell command entrypoint ``gping`` to ``setup.py``
+- Add argument parsing for interactive use, e.g. ``--hostnames=www.example.net,mail.example.net``
+- Incorporate "Make it possible to ping without root access" using ``socket.SOCK_DGRAM`` instead of ``socket.SOCK_RAW``
+ by Marko Tibold: https://github.com/markotibold/gping/commit/b75fa2d4
+- Incorporate "Allow binding to an interface", e.g. ``--bind=192.168.111.2``
+ by Dan Harvey: https://github.com/danharvey/pyping/commit/cb848976
+- Non-interactive mode: Record all results in ``self.results``
+- Non-interactive mode: Make verbose output optional
+
+2012-08-21 0.1
+==============
+- Fix setup.py deps
+- Add install instructions to README
+- Tag release ``gping-0.1``
+
+2012-07-17 0.0
+==============
+- Add main gping.py
+
+2012-07-12 0.0
+==============
+- Change __main__ action. Fix id overflow issue.
+
+2012-07-10 0.0
+==============
+- First commit. Clean out stuff. Fix setup.py.
+- Add README.md
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..9cc1267
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,11 @@
+The original code derived from ping.c distributed in Linux's netkit.
+That code is copyright (c) 1989 by The Regents of the University of California.
+That code is in turn derived from code written by Mike Muuss of the
+US Army Ballistic Research Laboratory in December, 1983 and
+placed in the public domain. They have my thanks.
+
+Copyright (c) Matthew Dixon Cowles, .
+Distributable under the terms of the GNU General Public License
+version 2. Provided with no warranties of any sort.
+
+See AUTHORS for complete list of authors and contributors.
\ No newline at end of file
diff --git a/README b/README
deleted file mode 100644
index 1488af0..0000000
--- a/README
+++ /dev/null
@@ -1,2 +0,0 @@
-Originally from http://svn.pylucid.net/pylucid/CodeSnippets/ping.py
-This version maintained at http://github.com/samuel/python-ping
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..da7e4e3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,59 @@
+# GPing #
+
+An asynchronous, event-driven, pure-python ping implementation using raw sockets based on gevent.
+This is a fork of the python-ping project replacing its internal machinery with gevent.
+The point is to have an event driven ping utility for doing a huge number of concurrent pings efficiently.
+
+
+## Usage ##
+
+### Run on the commandline ###
+
+ # Ping some hostnames
+ gping --hostnames=gnu.org,fsf.org,google.com,microsoft.com,googleusercontent.com,live.com,stackoverflow.com,141.1.1.1,8.8.8.8,192.168.123.1,192.168.999.1
+
+ # Bind to a specific IP address
+ gping --bind=192.168.111.2 --hostnames=google.com,stackoverflow.com,8.8.8.8
+
+### Demo with 100 concurrent pings ###
+
+ # Ping the top 100 domains
+ time python gping.py
+
+### Use as library ###
+
+ from gping import GPing
+
+ gp = GPing()
+ gp.send("127.0.0.1", test_callback)
+ gp.join()
+
+## Install ##
+
+### From Python Package Index ###
+This *should* be easy on your average \*nix box, just type:
+
+ sudo pip install gping
+
+
+### From GitHub ###
+This way of installing gping is suitable for hacking on it:
+
+ git clone https://github.com/mastahyeti/gping.git
+ cd gping
+ virtualenv .venv27
+ source .venv27/bin/activate
+ python setup.py develop
+
+## License and Credits ##
+
+The python-ping project was started by Matthew Dixon Cowles.
+
+ - copyleft 1989-2016 by the python-ping team, see AUTHORS for more details.
+ - license: GNU GPL v2, see LICENSE for more details.
+
+It was forked and ported to `gevent` by Ben Toews. Since then, this program is now called appropriately *GPing*.
+
+He says:
+> I have left the license and authors information intact, but this project seems to have a long history or forks and such
+> so I am probably somehow pissing someone off or violating some license. Let me know if this is the case and I will be better.
diff --git a/TODO.rst b/TODO.rst
new file mode 100644
index 0000000..542918e
--- /dev/null
+++ b/TODO.rst
@@ -0,0 +1,24 @@
+**********
+gping todo
+**********
+
+Tasks
+=====
+- [x] Add entrypoint ``gping`` and argument parsing
+- [o] Add reading from stdin
+- [o] Add collectd metrics gathering: https://pythonhosted.org/collectd/
+
+Upstream changes
+================
+- [x] Add "Make it possible to ping without root access.": https://github.com/markotibold/gping/commit/b75fa2d41ec10073f894676fc3f3ec6b46693c05
+- [o] Add "Allow binding to an interface": https://github.com/danharvey/pyping/commit/cb8489762d3171fb0b69c0fb9aaa8968d5e439b4
+- [o] Add statsd support: https://github.com/ChristianKniep/python-ping/commit/a3653526e5857f346e2a244988df3849574ba385
+- [o] Check "fix packet numbering bug": https://github.com/matesito/gping/commit/498c93500e35c8f5ad9c682df1e6c66fb5c5998a
+- [o] Check improvements from Vijayananda Reddy: https://github.com/VijayanandaReddy/gping/commit/25ac7c8efb6cf394b6c36ed2ed5b6712116b6c53
+- [o] Check "For some reason, die was not working": https://github.com/biplav/gping/commit/377f0f4e85535fd3b6f812eb29d49ad8bf9a24fa
+- [o] Check "Changes to harden gping.py for usecases like die, ping of devices, timeouts": https://github.com/biplav/gping/commit/6fb9008d4ae63f954f6d59cfbf4bb445964c1351
+- [o] Check features of leading non-gevent repositories (IPv6, etc.):
+
+ - https://github.com/l4m3rx/python-ping
+ - https://github.com/tomwilkie/pyping
+
diff --git a/gping.py b/gping.py
new file mode 100644
index 0000000..fdf4523
--- /dev/null
+++ b/gping.py
@@ -0,0 +1,333 @@
+"""
+ This part is a fork of the python-ping project that makes
+ things work with gevent.
+"""
+
+import os
+import struct
+import sys
+import time
+from args import args
+
+import gevent
+from gevent import socket
+from gevent.pool import Pool
+from gevent.event import Event
+
+# From /usr/include/linux/icmp.h; your milage may vary.
+ICMP_ECHO_REQUEST = 8 # Seems to be the same on Solaris.
+
+
+def checksum(source_string):
+ """
+ I'm not too confident that this is right but testing seems
+ to suggest that it gives the same answers as in_cksum in ping.c
+ """
+ sum = 0
+ count_to = (len(source_string) / 2) * 2
+ for count in xrange(0, count_to, 2):
+ this = ord(source_string[count + 1]) * 256 + ord(source_string[count])
+ sum = sum + this
+ sum = sum & 0xffffffff # Necessary?
+
+ if count_to < len(source_string):
+ sum = sum + ord(source_string[len(source_string) - 1])
+ sum = sum & 0xffffffff # Necessary?
+
+ sum = (sum >> 16) + (sum & 0xffff)
+ sum = sum + (sum >> 16)
+ answer = ~sum
+ answer = answer & 0xffff
+
+ # Swap bytes. Bugger me if I know why.
+ answer = answer >> 8 | (answer << 8 & 0xff00)
+
+ return answer
+
+
+class GPing:
+ """
+ This class, when instantiated will start listening for ICMP responses.
+ Then call its send method to send pings. Callbacks will be sent ping
+ details
+ """
+ def __init__(self, timeout=2, max_outstanding=10, bind=None, callback=None):
+ """
+ :timeout - amount of time a ICMP echo request can be outstanding
+ :max_outstanding - maximum number of outstanding ICMP echo requests without responses (limits traffic)
+ """
+ self.timeout = timeout
+ self.max_outstanding = max_outstanding
+ self.bind = bind
+ self.callback = callback
+
+ # id we will increment with each ping
+ self.id = 0
+
+ # Object to hold and keep track of all of our self.pings
+ self.pings = {}
+
+ # Keep track of results
+ self.results = []
+
+ # Keep track of failures
+ self.failures = []
+
+ # event to file when we want to shut down
+ self.die_event = Event()
+
+ # setup socket
+ icmp = socket.getprotobyname("icmp")
+ try:
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, icmp)
+ except socket.error, (errno, msg):
+ if errno == 1:
+ # Operation not permitted
+ msg = msg + (
+ " - Note that ICMP messages can only be sent from processes"
+ " running as root."
+ )
+ raise socket.error(msg)
+ raise # raise the original error
+
+ # Bind the socket to the interface of given IP address
+ if self.bind:
+ self.socket.bind((self.bind, 0)) # Port number is irrelevant for ICMP
+
+ self.receive_glet = gevent.spawn(self.__receive__)
+ self.processto_glet = gevent.spawn(self.__process_timeouts__)
+
+
+ def die(self):
+ """
+ try to shut everything down gracefully
+ """
+ print "shutting down"
+ self.die_event.set()
+ socket.cancel_wait()
+ gevent.joinall([self.receive_glet,self.processto_glet])
+
+
+ def join(self):
+ """
+ does a lot of nothing until self.pings is empty
+ """
+ while len(self.pings):
+ gevent.sleep()
+
+
+ def send(self, dest_addr, callback=None, psize=64):
+ """
+ Send a ICMP echo request.
+ :dest_addr - where to send it
+ :callback - what to call when we get a response
+ :psize - how much data to send with it
+ """
+
+ callback = callback or self.callback
+
+ # make sure we dont have too many outstanding requests
+ while len(self.pings) >= self.max_outstanding:
+ gevent.sleep(0.01)
+
+ # figure out our id
+ packet_id = self.id
+
+ # increment our id, but wrap if we go over the max size for USHORT
+ self.id = (self.id + 1) % 2 ** 16
+
+
+ # make a spot for this ping in self.pings
+ self.pings[packet_id] = {'sent':False,'success':False,'error':False,'dest_addr':dest_addr,'dest_ip':None,'callback':callback}
+
+ # Resolve hostname
+ try:
+ dest_ip = socket.gethostbyname(dest_addr)
+ self.pings[packet_id]['dest_ip'] = dest_ip
+ except socket.gaierror as ex:
+ self.pings[packet_id]['error'] = True
+ self.pings[packet_id]['message'] = str(ex)
+ return
+
+
+ # Remove header size from packet size
+ psize = psize - 8
+
+ # Header is type (8), code (8), checksum (16), id (16), sequence (16)
+ my_checksum = 0
+
+ # Make a dummy heder with a 0 checksum.
+ header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, my_checksum, packet_id, 1)
+ bytes = struct.calcsize("d")
+ data = (psize - bytes) * "Q"
+ data = struct.pack("d", time.time()) + data
+
+ # Calculate the checksum on the data and the dummy header.
+ my_checksum = checksum(header + data)
+
+ # Now that we have the right checksum, we put that in. It's just easier
+ # to make up a new header than to stuff it into the dummy.
+ header = struct.pack(
+ "bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), packet_id, 1
+ )
+ packet = header + data
+ # note the send_time for checking for timeouts
+ self.pings[packet_id]['send_time'] = time.time()
+
+ # send the packet
+ self.socket.sendto(packet, (dest_ip, 1)) # Don't know about the 1
+
+ #mark the packet as sent
+ self.pings[packet_id]['sent'] = True
+
+ def record_result(self, ping):
+
+ # Keep track of ping results
+ self.results.append(ping)
+
+ # Propagate individual callback
+ if 'callback' in ping and callable(ping['callback']):
+ ping['callback'](ping)
+
+ def __process_timeouts__(self):
+ """
+ check to see if any of our pings have timed out
+ """
+ while not self.die_event.is_set():
+ for i in self.pings:
+
+ # Detect timeout
+ if self.pings[i]['sent'] and time.time() - self.pings[i]['send_time'] > self.timeout:
+ self.pings[i]['error'] = True
+ self.pings[i]['message'] = 'Timeout after {} seconds'.format(self.timeout)
+
+ # Handle all failures
+ if self.pings[i]['error'] == True:
+ self.record_result(self.pings[i])
+ self.failures.append(self.pings[i])
+ del(self.pings[i])
+ break
+
+ gevent.sleep()
+
+
+ def __receive__(self):
+ """
+ receive response packets
+ """
+ while not self.die_event.is_set():
+ # wait till we can recv
+ try:
+ socket.wait_read(self.socket.fileno())
+ except socket.error, (errno,msg):
+ if errno == socket.EBADF:
+ print "interrupting wait_read"
+ return
+ # reraise original exceptions
+ print "re-throwing socket exception on wait_read()"
+ raise
+
+ time_received = time.time()
+ received_packet, addr = self.socket.recvfrom(1024)
+ icmpHeader = received_packet[20:28]
+ type, code, checksum, packet_id, sequence = struct.unpack(
+ "bbHHh", icmpHeader
+ )
+
+ if packet_id in self.pings:
+ bytes_received = struct.calcsize("d")
+ time_sent = struct.unpack("d", received_packet[28:28 + bytes_received])[0]
+ self.pings[packet_id]['delay'] = time_received - time_sent
+
+ # i'd call that a success
+ self.pings[packet_id]['success'] = True
+
+ # Record the ping result
+ self.record_result(self.pings[packet_id])
+
+ # delete the ping
+ del(self.pings[packet_id])
+
+ gevent.sleep()
+
+ def print_report(self):
+
+ # Output header
+ print >>sys.stderr
+ template = '{ip:20s}{delay:15s}{hostname:40s}{message}'
+ header = template.format(hostname='Hostname', ip='IP', delay='Delay', message='Message')
+ print >>sys.stderr, header
+
+ # Output results
+ for result in self.results:
+ message = self.format_ping_result(result)
+ print >>sys.stderr, message
+
+ # Output failures
+ print >>sys.stderr
+ print >>sys.stderr, 'Failures:'
+ template = '{hostname:45}{message}'
+ for failure in self.failures:
+ message = template.format(hostname=failure['dest_addr'], message=failure.get('message', 'unknown error'))
+ print >>sys.stderr, message
+
+ def format_ping_result(self, ping):
+ template = '{ip:20s}{delay:15s}{hostname:40s}{message}'
+ message = template.format(
+ hostname = ping['dest_addr'],
+ ip = ping['dest_ip'],
+ delay = ping['success'] and str(round(ping['delay'], 6)) or '',
+ message = 'message' in ping and ping['message'] or ''
+ )
+ message = message.strip()
+ return message
+
+
+def ping(hostnames, verbose=False, **options):
+ options = options or {}
+ gp = GPing(**options)
+
+ for hostname in hostnames:
+ gp.send(hostname)
+
+ gp.join()
+
+ if verbose:
+ gp.print_report()
+
+ return gp
+
+
+def run():
+
+ """
+ print 'Arguments passed in: ' + str(args.all)
+ print 'Flags detected: ' + str(args.flags)
+ print 'Files detected: ' + str(args.files)
+ print 'NOT files detected: ' + str(args.not_files)
+ print 'Grouped Arguments: ' + str(args.grouped)
+ print 'Assignments detected: ' + str(args.assignments)
+ """
+
+ # The --hostnames argument is obligatory
+ if '--hostnames' in args.assignments:
+
+ # Compute list of hostnames from argument
+ hostnames_raw = args.assignments['--hostnames'].get(0)
+ hostnames = hostnames_raw.split(',')
+
+ # Compute additional options from arguments
+ options = {}
+ if '--bind' in args.assignments:
+ options['bind'] = args.assignments['--bind'].get(0)
+
+ ping(hostnames, verbose=True, **options)
+
+ else:
+ raise ValueError('Please specify the --hostnames= argument for passing a list of comma-separated hostnames')
+
+
+if __name__ == '__main__':
+ top_100_domains = ['google.com','facebook.com','youtube.com','yahoo.com','baidu.com','wikipedia.org','live.com','qq.com','twitter.com','amazon.com','linkedin.com','blogspot.com','google.co.in','taobao.com','sina.com.cn','yahoo.co.jp','msn.com','google.com.hk','wordpress.com','google.de','google.co.jp','google.co.uk','ebay.com','yandex.ru','163.com','google.fr','weibo.com','googleusercontent.com','bing.com','microsoft.com','google.com.br','babylon.com','soso.com','apple.com','mail.ru','t.co','tumblr.com','vk.com','google.ru','sohu.com','google.es','pinterest.com','google.it','craigslist.org','bbc.co.uk','livejasmin.com','tudou.com','paypal.com','blogger.com','xhamster.com','ask.com','youku.com','fc2.com','google.com.mx','xvideos.com','google.ca','imdb.com','flickr.com','go.com','tmall.com','avg.com','ifeng.com','hao123.com','zedo.com','conduit.com','google.co.id','pornhub.com','adobe.com','blogspot.in','odnoklassniki.ru','google.com.tr','cnn.com','aol.com','360buy.com','google.com.au','rakuten.co.jp','about.com','mediafire.com','alibaba.com','ebay.de','espn.go.com','wordpress.org','chinaz.com','google.pl','stackoverflow.com','netflix.com','ebay.co.uk','uol.com.br','amazon.de','ameblo.jp','adf.ly','godaddy.com','huffingtonpost.com','amazon.co.jp','cnet.com','globo.com','youporn.com','4shared.com','thepiratebay.se','renren.com']
+ ping(top_100_domains, verbose=True)
+
diff --git a/ping.py b/ping.py
deleted file mode 100644
index af41f1e..0000000
--- a/ping.py
+++ /dev/null
@@ -1,217 +0,0 @@
-#!/usr/bin/env python
-
-"""
- A pure python ping implementation using raw socket.
-
-
- Note that ICMP messages can only be sent from processes running as root.
-
-
- Derived from ping.c distributed in Linux's netkit. That code is
- copyright (c) 1989 by The Regents of the University of California.
- That code is in turn derived from code written by Mike Muuss of the
- US Army Ballistic Research Laboratory in December, 1983 and
- placed in the public domain. They have my thanks.
-
- Bugs are naturally mine. I'd be glad to hear about them. There are
- certainly word - size dependenceies here.
-
- Copyright (c) Matthew Dixon Cowles, .
- Distributable under the terms of the GNU General Public License
- version 2. Provided with no warranties of any sort.
-
- Original Version from Matthew Dixon Cowles:
- -> ftp://ftp.visi.com/users/mdc/ping.py
-
- Rewrite by Jens Diemer:
- -> http://www.python-forum.de/post-69122.html#69122
-
-
- Revision history
- ~~~~~~~~~~~~~~~~
-
- March 11, 2010
- changes by Samuel Stauffer:
- - replaced time.clock with default_timer which is set to
- time.clock on windows and time.time on other systems.
-
- May 30, 2007
- little rewrite by Jens Diemer:
- - change socket asterisk import to a normal import
- - replace time.time() with time.clock()
- - delete "return None" (or change to "return" only)
- - in checksum() rename "str" to "source_string"
-
- November 22, 1997
- Initial hack. Doesn't do much, but rather than try to guess
- what features I (or others) will want in the future, I've only
- put in what I need now.
-
- December 16, 1997
- For some reason, the checksum bytes are in the wrong order when
- this is run under Solaris 2.X for SPARC but it works right under
- Linux x86. Since I don't know just what's wrong, I'll swap the
- bytes always and then do an htons().
-
- December 4, 2000
- Changed the struct.pack() calls to pack the checksum and ID as
- unsigned. My thanks to Jerome Poincheval for the fix.
-
-
- Last commit info:
- ~~~~~~~~~~~~~~~~~
- $LastChangedDate: $
- $Rev: $
- $Author: $
-"""
-
-
-import os, sys, socket, struct, select, time
-
-if sys.platform == "win32":
- # On Windows, the best timer is time.clock()
- default_timer = time.clock
-else:
- # On most other platforms the best timer is time.time()
- default_timer = time.time
-
-# From /usr/include/linux/icmp.h; your milage may vary.
-ICMP_ECHO_REQUEST = 8 # Seems to be the same on Solaris.
-
-
-def checksum(source_string):
- """
- I'm not too confident that this is right but testing seems
- to suggest that it gives the same answers as in_cksum in ping.c
- """
- sum = 0
- countTo = (len(source_string)/2)*2
- count = 0
- while count> 16) + (sum & 0xffff)
- sum = sum + (sum >> 16)
- answer = ~sum
- answer = answer & 0xffff
-
- # Swap bytes. Bugger me if I know why.
- answer = answer >> 8 | (answer << 8 & 0xff00)
-
- return answer
-
-
-def receive_one_ping(my_socket, ID, timeout):
- """
- receive the ping from the socket.
- """
- timeLeft = timeout
- while True:
- startedSelect = default_timer()
- whatReady = select.select([my_socket], [], [], timeLeft)
- howLongInSelect = (default_timer() - startedSelect)
- if whatReady[0] == []: # Timeout
- return
-
- timeReceived = default_timer()
- recPacket, addr = my_socket.recvfrom(1024)
- icmpHeader = recPacket[20:28]
- type, code, checksum, packetID, sequence = struct.unpack(
- "bbHHh", icmpHeader
- )
- if packetID == ID:
- bytesInDouble = struct.calcsize("d")
- timeSent = struct.unpack("d", recPacket[28:28 + bytesInDouble])[0]
- return timeReceived - timeSent
-
- timeLeft = timeLeft - howLongInSelect
- if timeLeft <= 0:
- return
-
-
-def send_one_ping(my_socket, dest_addr, ID):
- """
- Send one ping to the given >dest_addr<.
- """
- dest_addr = socket.gethostbyname(dest_addr)
-
- # Header is type (8), code (8), checksum (16), id (16), sequence (16)
- my_checksum = 0
-
- # Make a dummy heder with a 0 checksum.
- header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, my_checksum, ID, 1)
- bytesInDouble = struct.calcsize("d")
- data = (192 - bytesInDouble) * "Q"
- data = struct.pack("d", default_timer()) + data
-
- # Calculate the checksum on the data and the dummy header.
- my_checksum = checksum(header + data)
-
- # Now that we have the right checksum, we put that in. It's just easier
- # to make up a new header than to stuff it into the dummy.
- header = struct.pack(
- "bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1
- )
- packet = header + data
- my_socket.sendto(packet, (dest_addr, 1)) # Don't know about the 1
-
-
-def do_one(dest_addr, timeout):
- """
- Returns either the delay (in seconds) or none on timeout.
- """
- icmp = socket.getprotobyname("icmp")
- try:
- my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
- except socket.error, (errno, msg):
- if errno == 1:
- # Operation not permitted
- msg = msg + (
- " - Note that ICMP messages can only be sent from processes"
- " running as root."
- )
- raise socket.error(msg)
- raise # raise the original error
-
- my_ID = os.getpid() & 0xFFFF
-
- send_one_ping(my_socket, dest_addr, my_ID)
- delay = receive_one_ping(my_socket, my_ID, timeout)
-
- my_socket.close()
- return delay
-
-
-def verbose_ping(dest_addr, timeout = 2, count = 4):
- """
- Send >count< ping to >dest_addr< with the given >timeout< and display
- the result.
- """
- for i in xrange(count):
- print "ping %s..." % dest_addr,
- try:
- delay = do_one(dest_addr, timeout)
- except socket.gaierror, e:
- print "failed. (socket error: '%s')" % e[1]
- break
-
- if delay == None:
- print "failed. (timeout within %ssec.)" % timeout
- else:
- delay = delay * 1000
- print "get ping in %0.4fms" % delay
- print
-
-
-if __name__ == '__main__':
- verbose_ping("heise.de")
- verbose_ping("google.com")
- verbose_ping("a-test-url-taht-is-not-available.com")
- verbose_ping("192.168.1.1")
diff --git a/ping_header_info.txt b/ping_header_info.txt
new file mode 100644
index 0000000..371c729
--- /dev/null
+++ b/ping_header_info.txt
@@ -0,0 +1,50 @@
+IP header info from RFC791
+ -> http://tools.ietf.org/html/rfc791)
+
+0 1 2 3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|Version| IHL |Type of Service| Total Length |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Identification |Flags| Fragment Offset |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Time to Live | Protocol | Header Checksum |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Source Address |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Destination Address |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Options | Padding |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+===========================================================================
+ICMP Echo / Echo Reply Message header info from RFC792
+ -> http://tools.ietf.org/html/rfc792
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identifier | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Data ...
+ +-+-+-+-+-
+
+===========================================================================
+ICMP parameter info:
+ -> http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml
+
+===========================================================================
+An example of ping's typical output:
+
+PING heise.de (193.99.144.80): 56 data bytes
+64 bytes from 193.99.144.80: icmp_seq=0 ttl=240 time=127 ms
+64 bytes from 193.99.144.80: icmp_seq=1 ttl=240 time=127 ms
+64 bytes from 193.99.144.80: icmp_seq=2 ttl=240 time=126 ms
+64 bytes from 193.99.144.80: icmp_seq=3 ttl=240 time=126 ms
+64 bytes from 193.99.144.80: icmp_seq=4 ttl=240 time=127 ms
+
+----heise.de PING Statistics----
+5 packets transmitted, 5 packets received, 0.0% packet loss
+round-trip (ms) min/avg/max/med = 126/127/127/127
\ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..e8860b3
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+"""
+ distutils setup
+ ~~~~~~~~~~~~~~~
+
+ :homepage: https://github.com/mastahyeti/gping/
+ :copyleft: 1989-2011 by the python-ping team, see AUTHORS for more details.
+ :license: GNU GPL v2, see LICENSE for more details.
+"""
+
+import os
+
+from setuptools import setup, find_packages, Command
+
+def get_authors():
+ authors = []
+ try:
+ f = file(os.path.join(PACKAGE_ROOT, "AUTHORS"), "r")
+ for line in f:
+ if not line.strip().startswith("*"):
+ continue
+ if "--" in line:
+ line = line.split("--", 1)[0]
+ authors.append(line.strip(" *\r\n"))
+ f.close()
+ authors.sort()
+ except Exception, err:
+ authors = "[Error: %s]" % err
+ return authors
+
+
+setup(
+ name='gping',
+ version="0.2",
+ description='A gevent fork of python-ping.',
+ author=get_authors(),
+ maintainer="Ben Toews",
+ maintainer_email="mastahyeti@gmail.com",
+ url='https://github.com/mastahyeti/gping',
+ keywords="ping icmp network latency gevent",
+ py_modules=['gping'],
+ install_requires=['gevent', 'args'],
+ dependency_links=[
+ 'https://github.com/kennethreitz/args/tarball/0a6d5eb#egg=args',
+ ],
+ entry_points={
+ 'console_scripts': [
+ 'gping = gping:run',
+ ],
+ },
+)