ping 0.1.0.1 → 0.1.0.2
raw patch · 6 files changed
+82/−22 lines, 6 filesdep ~posix-api
Dependency ranges changed: posix-api
Files
- CHANGELOG.md +17/−3
- README.md +45/−0
- ping.cabal +4/−3
- src/Network/Icmp/Ping/Hosts.hs +6/−6
- src/Network/Icmp/Ping/Multihosts.hs +5/−5
- src/Network/Icmp/Ping/Single.hs +5/−5
CHANGELOG.md view
@@ -1,5 +1,19 @@-# Revision history for ping+# Changelog+All notable changes to this project will be documented in this file. -## 0.1.0.0 -- YYYY-mm-dd+The format is inspired by [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).+This changelog deviates from the recommendation by not grouping changes into+added, changed, deprecated, etc. subsections. -* First version. Released on an unsuspecting world.+This project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/).++## [0.1.0.1] - 2018-01-07+- Fix a problem in `multihosts` that occassionally caused the function+ to wait for a number of nanoseconds close to `maxBound :: Word64`.+ This had been caused by a subtraction underflow.++## [0.1.0.0] - 2018-01-02+- Initial release.+- Function `host` for pinging a single host once.+- Function `hosts` and `range` for pinging multiple hosts once each.+- Function `multihosts` and `multirange` for pinging multiple hosts once each.
+ README.md view
@@ -0,0 +1,45 @@+# ping++## Objective++This library provides high-performance functions that issue ICMP echo+requests and wait for responses, measuring the elapsed time. It is intended+to be cross-platform as possible, and it may use any system APIs available.+However, it will not resort to running `/bin/ping` as a subprocess. Pull+requests that improve compatibility will accepted so long as they do not+start a subprocess.++## Build Instructions++This library relies on `posix-api`, which needs a currently-unreleased+version of `hsc2hs` in order to build. In order to try out this library, try:++```+~/dev $ git clone https://github.com/haskell/hsc2hs+~/dev $ cd hsc2hs+~/dev/hsc2hs $ cabal install+~/dev/hsc2hs $ cd ..+~/dev $ git clone https://github.com/andrewthad/ping+~/dev $ cd ping+~/dev/ping $ cabal new-build --with-hsc2hs=~/.cabal/bin/hsc2hs+```++This will build all dependencies, including `posix-api`, with the+upstream `hsc2hs` tool.++## Infelicities++This project's objective is to be cross-platform. However, it does not+accomplish this. The author primarily runs a Debian Linux distribution+and consequently lacks the resources and the motivation to make this+work on other platforms. Contributions to improve compatibility are+welcomed. Current known problems include:++- On Linux, the library should fallback to using raw sockets if `IPPROTO_ICMP`+ does not work.+- Support for Windows is missing.+- Support for BSD is missing. However, adding raw socket support to improve+ the situation on Linux may fix this as well.+- Support for Darwin is missing. This should not be difficult since+ Darwin supports `IPPROTO_ICMP` sockets.+
ping.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: ping-version: 0.1.0.1+version: 0.1.0.2 synopsis: icmp echo requests description: This library provides functions that have similar behavior as the@@ -23,11 +23,12 @@ license-file: LICENSE author: Andrew Martin maintainer: andrew.thaddeus@gmail.com-copyright: 2018 Andrew Martin+copyright: 2019 Andrew Martin category: Network build-type: Simple extra-source-files: CHANGELOG.md+ README.md include/custom.h flag debug@@ -45,7 +46,7 @@ , base >= 4.11.1 && <5 , ip >= 1.4 , cpu >= 0.1.2- , posix-api >= 0.1+ , posix-api >= 0.2.1 && < 0.3 , primitive >= 0.6.4 , primitive-containers >= 0.3.1 , stm >= 2.5
src/Network/Icmp/Ping/Hosts.hs view
@@ -120,7 +120,7 @@ -> SU.Set IPv4 -- ^ Hosts -> IO (Either IcmpException (MUU.Map IPv4 Word64)) -- ^ Elapsed nanoseconds for responding hosts hosts !pause !theHosts = do- mask $ \restore -> SCK.socket SCK.internet SCK.datagram SCK.icmp >>= \case+ mask $ \restore -> SCK.uninterruptibleSocket SCK.internet SCK.datagram SCK.icmp >>= \case Left (Errno e) -> pure (Left (IcmpExceptionSocket e)) Right sock -> do durations <- restore@@ -140,8 +140,8 @@ ) ) `onException`- (SCK.unsafeClose sock)- SCK.unsafeClose sock >>= \case+ (SCK.uninterruptibleClose sock)+ SCK.uninterruptibleClose sock >>= \case Left (Errno e) -> pure (Left (IcmpExceptionClose e)) Right _ -> pure durations @@ -153,7 +153,7 @@ waitForReadWrite sock >>= \case True -> do debug "ready for read"- r <- SCK.unsafeReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait+ r <- SCK.uninterruptibleReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait case r of Left (Errno e) -> pure (Left (IcmpExceptionReceive e)) Right receivedBytes -> if receivedBytes == intToCSize fullPacketSize@@ -185,7 +185,7 @@ pokeIcmpHeader buffer (intToWord16 ix) (getIPv4 host) let sockaddr = SCK.encodeSocketAddressInternet (SocketAddressInternet { port = 0, address = toBE32 (getIPv4 host) })- mwriteError <- SCK.unsafeSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr+ mwriteError <- SCK.uninterruptibleSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr case mwriteError of Left (Errno e) -- When you try to send a packet to a broadcast address, the kernel@@ -221,7 +221,7 @@ isReady <- waitForRead remainingMicroseconds sock if isReady then do- r <- SCK.unsafeReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait+ r <- SCK.uninterruptibleReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait case r of Left (Errno e) -> pure (Left (IcmpExceptionReceive e)) Right receivedBytes -> if receivedBytes == intToCSize fullPacketSize
src/Network/Icmp/Ping/Multihosts.hs view
@@ -121,7 +121,7 @@ -- over the course of the loop's execution. multihosts !pause !successPause' !totalPings !cutoff !theHosts | pause <= 0 || totalPings <= 0 || cutoff <= 0 || SU.null theHosts = pure (Right mempty)- | otherwise = let !successPause = max successPause' 0 in mask $ \restore -> SCK.socket SCK.internet SCK.datagram SCK.icmp >>= \case+ | otherwise = let !successPause = max successPause' 0 in mask $ \restore -> SCK.uninterruptibleSocket SCK.internet SCK.datagram SCK.icmp >>= \case Left (Errno e) -> pure (Left (IcmpExceptionSocket e)) Right sock -> do !now0 <- getMonotonicTimeNSec@@ -155,7 +155,7 @@ waitForRead shouldRead (word64ToInt microPause) sock >>= \case True -> do debug "Receiving in poll loop"- r <- SCK.unsafeReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait+ r <- SCK.uninterruptibleReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait case r of Left (Errno e) -> pure (Left (IcmpExceptionReceive e)) Right receivedBytes -> if receivedBytes == intToCSize fullPacketSize@@ -210,8 +210,8 @@ ) ) `onException`- (SCK.unsafeClose sock)- SCK.unsafeClose sock >>= \case+ (SCK.uninterruptibleClose sock)+ SCK.uninterruptibleClose sock >>= \case Left (Errno e) -> pure (Left (IcmpExceptionClose e)) Right _ -> pure durations @@ -269,7 +269,7 @@ let sockaddr = SCK.encodeSocketAddressInternet (SocketAddressInternet { port = 0, address = toBE32 (getIPv4 theHost) }) mwriteError <- writeWhenReady- (SCK.unsafeSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr)+ (SCK.uninterruptibleSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr) (threadWaitWrite sock) case mwriteError of Left (Errno e)
src/Network/Icmp/Ping/Single.hs view
@@ -49,7 +49,7 @@ -- has a fancy way to display the failure. The user will likely need to -- rerun the program with CAP_NET_RAW or as root or after adjusting -- net.ipv4.ping_group_range with sysctl.- mask $ \restore -> SCK.socket SCK.internet SCK.datagram SCK.icmp >>= \case+ mask $ \restore -> SCK.uninterruptibleSocket SCK.internet SCK.datagram SCK.icmp >>= \case Left (Errno e) -> pure (Left (IcmpExceptionSocket e)) Right sock -> do elapsed <- restore@@ -61,7 +61,7 @@ pokeIcmpHeader buffer 0 w start <- getMonotonicTimeNSec mwriteError <- writeWhenReady- (SCK.unsafeSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr)+ (SCK.uninterruptibleSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr) (threadWaitWrite sock) case mwriteError of Left (Errno e)@@ -75,7 +75,7 @@ isReady <- waitForRead maxWaitTime sock if isReady then do- r <- SCK.unsafeReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait+ r <- SCK.uninterruptibleReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait case r of Left (Errno e) -> pure (Left (IcmpExceptionReceive e)) Right receivedBytes -> if receivedBytes == intToCSize fullPacketSize@@ -98,10 +98,10 @@ -- by unsafeClose (not that we expect to see any). We do this -- because there is no other sensible behavior. We would much -- rather preserve the original exception.- (SCK.unsafeClose sock)+ (SCK.uninterruptibleClose sock) -- It is not neccessary to use closeFdWith here since the socket -- cannot possibly be seen by more than one thread.- SCK.unsafeClose sock >>= \case+ SCK.uninterruptibleClose sock >>= \case Left (Errno e) -> pure (Left (IcmpExceptionClose e)) Right _ -> pure elapsed