hid: figured out how to port timeouts
This commit is contained in:
		
							
								
								
									
										84
									
								
								hid/main.go
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								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 ""
 | 
			
		||||
	})
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user