|
|
@@ -0,0 +1,62 @@
|
|
|
+package ws
|
|
|
+
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "net"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+type StoppableListener struct {
|
|
|
+ *net.TCPListener //Wrapped listener
|
|
|
+ stop chan int //Channel used only to indicate listener should shutdown
|
|
|
+}
|
|
|
+
|
|
|
+func NewStoppableListener(l net.Listener) (*StoppableListener, error) {
|
|
|
+ tcpL, ok := l.(*net.TCPListener)
|
|
|
+
|
|
|
+ if !ok {
|
|
|
+ return nil, errors.New("Cannot wrap listener")
|
|
|
+ }
|
|
|
+
|
|
|
+ retval := &StoppableListener{}
|
|
|
+ retval.TCPListener = tcpL
|
|
|
+ retval.stop = make(chan int)
|
|
|
+
|
|
|
+ return retval, nil
|
|
|
+}
|
|
|
+
|
|
|
+var StoppedError = errors.New("Listener stopped")
|
|
|
+
|
|
|
+func (sl *StoppableListener) Accept() (net.Conn, error) {
|
|
|
+
|
|
|
+ for {
|
|
|
+ //Wait up to one second for a new connection
|
|
|
+ sl.SetDeadline(time.Now().Add(time.Second))
|
|
|
+
|
|
|
+ newConn, err := sl.TCPListener.Accept()
|
|
|
+
|
|
|
+ //Check for the channel being closed
|
|
|
+ select {
|
|
|
+ case <-sl.stop:
|
|
|
+ return nil, StoppedError
|
|
|
+ default:
|
|
|
+ //If the channel is still open, continue as normal
|
|
|
+ }
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ netErr, ok := err.(net.Error)
|
|
|
+
|
|
|
+ //If this is a timeout, then continue to wait for
|
|
|
+ //new connections
|
|
|
+ if ok && netErr.Timeout() && netErr.Temporary() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return newConn, err
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (sl *StoppableListener) Stop() {
|
|
|
+ close(sl.stop)
|
|
|
+}
|