diff options
| author | Přemysl Janouch <p@janouch.name> | 2018-08-01 17:49:27 +0200 | 
|---|---|---|
| committer | Přemysl Janouch <p@janouch.name> | 2018-08-01 20:39:37 +0200 | 
| commit | e0b46a8cff40e9a6d965a18900572c4832e1d075 (patch) | |
| tree | 8cccb2d8247ca7e4fde4e23d1e83323fc5849547 | |
| parent | a6e6c3aaffa8f25aefed5502cdb42a18124b96e2 (diff) | |
| download | haven-e0b46a8cff40e9a6d965a18900572c4832e1d075.tar.gz haven-e0b46a8cff40e9a6d965a18900572c4832e1d075.tar.xz haven-e0b46a8cff40e9a6d965a18900572c4832e1d075.zip | |
hid: figured out how to port timeouts
| -rw-r--r-- | hid/main.go | 84 | 
1 files changed, 64 insertions, 20 deletions
| diff --git a/hid/main.go b/hid/main.go index bcf7bc6..c3b2875 100644 --- a/hid/main.go +++ b/hid/main.go @@ -761,7 +761,7 @@ var (  	config         simpleConfig            // server configuration  	serverName     string                  // our server name -	pingInterval   uint                    // ping interval in seconds +	pingInterval   time.Duration           // ping interval  	maxConnections int                     // max connections allowed or 0  	motd           []string                // MOTD (none if empty)  	operators      = make(map[string]bool) // TLS cert. fingerprints for IRCops @@ -773,7 +773,7 @@ var (  	prepared = make(chan preparedEvent)  	reads    = make(chan readEvent)  	writes   = make(chan writeEvent) -	timeouts = make(chan *client) +	timers   = make(chan func())  	tlsConf   *tls.Config  	clients   = make(map[*client]bool) @@ -962,12 +962,7 @@ func (c *client) kill(reason string) {  		_ = c.transport.Close()  	} -	// Clean up the goroutine, although a spurious event may still be sent. -	// TODO: Other timers if needed. -	if c.killTimer != nil { -		c.killTimer.Stop() -	} - +	c.cancelTimers()  	delete(clients, c)  } @@ -994,9 +989,7 @@ func (c *client) closeLink(reason string) {  	c.closing = true  	c.unregister(reason) -	c.killTimer = time.AfterFunc(3*time.Second, func() { -		timeouts <- c -	}) +	c.setKillTimer()  }  func (c *client) inMaskList(masks []string) bool { @@ -1025,7 +1018,57 @@ func (c *client) getTLSCertFingerprint() string {  // --- Timers ------------------------------------------------------------------ -// TODO +// Free the resources of timers that haven't fired yet and for timers that are +// in between firing and being collected by the event loop, mark that the event +// should not be acted upon. +func (c *client) cancelTimers() { +	for _, timer := range []**time.Timer{ +		&c.killTimer, &c.timeoutTimer, &c.pingTimer, +	} { +		if *timer != nil { +			(*timer).Stop() +			*timer = nil +		} +	} +} + +// Arrange for a function to be called later from the main goroutine. +func (c *client) setTimer(timer **time.Timer, delay time.Duration, cb func()) { +	c.cancelTimers() + +	var identityCapture *time.Timer +	identityCapture = time.AfterFunc(delay, func() { +		timers <- func() { +			// The timer might have been cancelled or even replaced. +			// When the client is killed, this will be nil. +			if *timer == identityCapture { +				cb() +			} +		} +	}) + +	*timer = identityCapture +} + +func (c *client) setKillTimer() { +	c.setTimer(&c.killTimer, pingInterval, func() { +		c.kill("Timeout") +	}) +} + +func (c *client) setTimeoutTimer() { +	c.setTimer(&c.timeoutTimer, pingInterval, func() { +		c.closeLink(fmt.Sprintf("Ping timeout: >%d seconds", +			pingInterval/time.Second)) +	}) +} + +func (c *client) setPingTimer() { +	c.setTimer(&c.pingTimer, pingInterval, func() { +		c.sendf("PING :%s", serverName) +		c.setTimeoutTimer() +	}) +}  // --- IRC command handling ---------------------------------------------------- @@ -1451,7 +1494,7 @@ func ircHandlePONG(msg *message, c *client) {  	}  	// Set a new timer to send another PING -	// TODO +	c.setPingTimer()  }  func ircHandleQUIT(msg *message, c *client) { @@ -2817,6 +2860,7 @@ func (c *client) onPrepared(host string, isTLS bool) {  	// If we tried to send any data before now, we would need to flushSendQ.  	go read(c)  	c.reading = true +	c.setPingTimer()  }  // Handle the results from trying to read from the client connection. @@ -2996,6 +3040,9 @@ func processOneEvent() {  	case <-quitTimer:  		forceQuit("timeout") +	case callback := <-timers: +		callback() +  	case conn := <-conns:  		if maxConnections > 0 && len(clients) >= maxConnections {  			log.Println("connection limit reached, refusing connection") @@ -3026,6 +3073,9 @@ func processOneEvent() {  		clients[c] = true  		go prepare(c) +		// The TLS autodetection in prepare needs to have a timeout. +		c.setKillTimer() +  	case ev := <-prepared:  		log.Println("client is ready:", ev.host)  		if _, ok := clients[ev.client]; ok { @@ -3043,12 +3093,6 @@ func processOneEvent() {  		if _, ok := clients[ev.client]; ok {  			ev.client.onWrite(ev.written, ev.err)  		} - -	case c := <-timeouts: -		if _, ok := clients[c]; ok { -			log.Println("client timeouted") -			c.kill("TODO") -		}  	}  } @@ -3147,7 +3191,7 @@ func ircParseConfig() error {  		} else if u < 1 {  			return "the value is out of range"  		} else { -			pingInterval = uint(u) +			pingInterval = time.Second * time.Duration(u)  		}  		return ""  	}) | 
