Skip to content

Commit

Permalink
rewrote sigint handling
Browse files Browse the repository at this point in the history
  • Loading branch information
rbarazzutti committed Dec 6, 2021
1 parent 4123cb4 commit 7ce546f
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 83 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@

`http-ping` is a free software distributed under the [Apache License 2.0](LICENSE).

This piece of software is similar to the usual [_ping networking utility_](https://en.wikipedia.org/wiki/Ping_(networking_utility)) but instead of working on top of ICMP`, it works on top of
This piece of software is similar to the usual [_ping networking utility_](https://en.wikipedia.org/wiki/Ping_(networking_utility)) but instead of working on top of ICMP, it works on top of
HTTP/S.

is a small, free, easy-to-use command line utility that probes a given URL and displays relevant statistics. It is similar to the popular ping utility, but works over HTTP/S instead of ICMP, and with a URL instead of a computer name/IP address. http-ping supports IPv6 addresses.
Http-Ping is a small, free, easy-to-use command line utility that probes a given URL and displays relevant statistics. It is similar to the popular ping utility, but works over HTTP/S instead of ICMP, and with a URL instead of a computer name/IP address. http-ping supports IPv6 addresses.

## Platforms

This software is written in [Go](https://go.dev), and should then benefit from the [wide list of targets provided by Go](https://go.dev/doc/install/source#environment).

This software has been reported to work well on:
- *Linux:* amd64, 386, arm64, arm
- *Windows:* amd64, 386
- *Windows:* amd64, 386, arm64
- *MacOS:* amd64 (Intel Macs), arm64 (Apple Silicon)

## Usage
Expand Down
63 changes: 35 additions & 28 deletions app/httpping.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,63 @@ package app
import (
"fmt"
"github.com/fever-ch/http-ping/stats"
"github.com/fever-ch/http-ping/util"
"net/url"
"os"
"os/signal"
"time"
)

// HTTPPing actually does the pinging specified in config
func HTTPPing(config *Config) {
ic := make(chan os.Signal, 1)

u, _ := url.Parse(config.Target)
signal.Notify(ic, os.Interrupt)

client, err := NewWebClient(config)
pinger, err := NewPinger(config)

if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%s (%s)\n", err, config.IPProtocol)
fmt.Printf("Error: %s\n", err.Error())
os.Exit(1)
}

fmt.Printf("HTTP-PING %s (%s) %s\n", u.String(), client.connTarget, config.Method)
ch := pinger.Ping()

var latencies []time.Duration

sh := util.NewSignalHandler(os.Interrupt)

_ = client.DoMeasure()
sh.Sleep(config.Interval)
fmt.Printf("HTTP-PING %s (%s) %s\n", pinger.client.url.String(), pinger.client.connTarget, config.Method)

var latencies []time.Duration
attempts, failures := 0, 0

for a := int64(0); a < config.Count && !sh.Triggered(); a++ {
attempts++
if measure := client.DoMeasure(); !measure.IsFailure {
if config.LogLevel == 1 {
fmt.Printf("%4d: code=%d size=%d time=%.3f ms\n", a, measure.StatusCode, measure.Bytes, float64(measure.Duration.Nanoseconds())/1e6)
} else if config.LogLevel == 2 {
fmt.Printf("%4d: code=%d conn-reused=%t size=%d in=%d out=%d time=%.3f ms\n", a, measure.StatusCode, measure.SocketReused, measure.Bytes, measure.InBytes, measure.OutBytes, float64(measure.Duration.Nanoseconds())/1e6)
var loop = true
for loop {
select {
case measure := <-ch:
{
if measure == nil {
loop = false
} else {
if !measure.IsFailure {
if config.LogLevel == 1 {
fmt.Printf("%4d: code=%d size=%d time=%.3f ms\n", attempts, measure.StatusCode, measure.Bytes, float64(measure.Duration.Nanoseconds())/1e6)
} else if config.LogLevel == 2 {
fmt.Printf("%4d: code=%d conn-reused=%t size=%d in=%d out=%d time=%.3f ms\n", attempts, measure.StatusCode, measure.SocketReused, measure.Bytes, measure.InBytes, measure.OutBytes, float64(measure.Duration.Nanoseconds())/1e6)
}
latencies = append(latencies, measure.Duration)
} else {
if config.LogLevel >= 1 {
fmt.Printf("%4d: %s\n", attempts, measure.FailureCause)
}
failures++
}
attempts++
}
}
latencies = append(latencies, measure.Duration)
} else {
failures++
if config.LogLevel >= 1 {
fmt.Printf("%4d: %s\n", a, measure.FailureCause)
case <-ic:
{
loop = false
}
}
if a < config.Count {
sh.Sleep(config.Interval)
}
}

fmt.Printf("\n--- %s (%s) ping statistics ---\n", u.String(), client.connTarget)
fmt.Printf("\n--- %s (%s) ping statistics ---\n", pinger.client.url.String(), pinger.client.connTarget)
var lossRate = float64(0)
if len(latencies) > 0 {
lossRate = float64(100*failures) / float64(attempts)
Expand Down
40 changes: 40 additions & 0 deletions app/pinger.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,43 @@ type Answer struct {
func (a *Answer) String() string {
return fmt.Sprintf("code=%d size=%d conn-reused=%t time=%.3f ms", a.StatusCode, a.Bytes, a.SocketReused, float64(a.Duration.Nanoseconds())/1e6)
}

// Pinger is responsible of actually doing the HTTP pings
type Pinger struct {
client *WebClient
config *Config
}

// NewPinger builds a new Pinger
func NewPinger(config *Config) (*Pinger, error) {

pinger := Pinger{}

pinger.config = config

client, err := NewWebClient(config)

if err != nil {
return nil, fmt.Errorf("%s (%s)", err, config.IPProtocol)
}

pinger.client = client

return &pinger, nil
}

// Ping actually does the pinging specified in config
func (pinger *Pinger) Ping() <-chan *Answer {
measures := make(chan *Answer)
go func() {
pinger.client.DoMeasure()

for a := int64(0); a < pinger.config.Count; a++ {
measures <- pinger.client.DoMeasure()
time.Sleep(pinger.config.Interval)
}

close(measures)
}()
return measures
}
28 changes: 24 additions & 4 deletions app/webclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,28 @@ func NewWebClient(config *Config) (*WebClient, error) {
}

webClient.httpClient.Transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: webClient.dialCtx,
Proxy: http.ProxyFromEnvironment,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dialer := &net.Dialer{}
conn, err := dialer.DialContext(ctx, network, webClient.connTarget)
if err != nil {
return conn, err
}
return webClient.connCounter.Bind(conn), nil
},
DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
netDialer := &net.Dialer{}

tlsDialer := &tls.Dialer{
NetDialer: netDialer,
}
conn, err := tlsDialer.DialContext(ctx, network, addr)
if err != nil {
return conn, err
}
return conn, err
},

ForceAttemptHTTP2: true,
MaxIdleConns: 100,
DisableKeepAlives: webClient.config.DisableKeepAlive,
Expand Down Expand Up @@ -118,7 +138,7 @@ func (webClient *WebClient) DoMeasure() *Answer {
q := req.URL.Query()

if webClient.config.ExtraParam {
q.Add("extra_parameter_httpping", fmt.Sprintf("%X", time.Now().UnixMicro()))
q.Add("extra_parameter_http_ping", fmt.Sprintf("%X", time.Now().UnixMicro()))
}

for _, c := range webClient.config.Parameters {
Expand All @@ -143,7 +163,7 @@ func (webClient *WebClient) DoMeasure() *Answer {
if err != nil {
return &Answer{
IsFailure: true,
FailureCause: "Request timeout",
FailureCause: err.Error(),
}
}

Expand Down
19 changes: 19 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,25 @@ func prepareRootCmd() *cobra.Command {
}

config.Target = args[0]
//ch := app.HTTPPingE(&config)
//
//count := 0
//failures := 0
//for measure := range ch {
// if !measure.IsFailure {
// if config.LogLevel == 1 {
// fmt.Printf("%4d: code=%d size=%d time=%.2f ms\n", count, measure.StatusCode, measure.Bytes, float64(measure.Duration.Nanoseconds())/1e6)
// } else if config.LogLevel == 2 {
// fmt.Printf("%4d: code=%d conn-reused=%t size=%d in=%d out=%d time=%.2f ms\n", count, measure.StatusCode, measure.SocketReused, measure.Bytes, measure.InBytes, measure.OutBytes, float64(measure.Duration.Nanoseconds())/1e6)
// }
// } else {
// fmt.Printf("%4d: %s\n", count, measure.FailureCause)
// failures++
// }
// count++
//
//}

app.HTTPPing(&config)

return nil
Expand Down
48 changes: 0 additions & 48 deletions util/signal.go

This file was deleted.

0 comments on commit 7ce546f

Please sign in to comment.