Ver código fonte

These allow for shutdown.

Shutdown in testdoor is different then the tests.
Because I can't close the socket in testdoor,
I can in tests.
Steve Thielemann 3 anos atrás
pai
commit
5a825aa239

+ 24 - 31
door/door.go

@@ -26,12 +26,12 @@ import (
 	"log"
 	"os"
 	"path/filepath"
+	"runtime/debug"
 	"strconv"
 	"strings"
 	"sync"
-	"time"
-	"runtime/debug"
 	"sync/atomic"
+	"time"
 )
 
 const SavePos = "\x1b[s"              // Save Cursor Position
@@ -80,19 +80,19 @@ type DropfileConfig struct {
 }
 
 type Door struct {
-	Config        DropfileConfig
-	READFD        int
-	WRITEFD       int
-	Disconnected  int32	// atomic bool      // Has User disconnected/Hung up?
-	TimeOut       time.Time // Fixed point in time, when time expires
-	StartTime     time.Time // Time when User started door
-	Pushback      FIFOBuffer
-	LastColor     []int
-	readerChannel chan byte   // Reading from the User
-	writerChannel chan string // Writing to the User
-	closeChannel  chan bool   // Closing
-	wg            sync.WaitGroup
-	writerMutex   sync.Mutex
+	Config         DropfileConfig
+	READFD         int
+	WRITEFD        int
+	Disconnected   int32     // atomic bool      // Has User disconnected/Hung up?
+	TimeOut        time.Time // Fixed point in time, when time expires
+	StartTime      time.Time // Time when User started door
+	Pushback       FIFOBuffer
+	LastColor      []int       // Track the last color sent for restore color
+	readerChannel  chan byte   // Reading from the User
+	ReaderCanClose bool        // We can close the reader (in tests)
+	writerChannel  chan string // Writing to the User
+	closeChannel   chan bool   // Closing
+	wg             sync.WaitGroup
 }
 
 // Return the amount of time left as time.Duration
@@ -291,26 +291,19 @@ func (d *Door) Init(doorname string) {
 }
 
 func (d *Door) Close() {
-        defer func() {
-                if err := recover(); err != nil {
-                        log.Println("door.Close FAILURE:", err)
-                        // This displays stack trace stderr
-                        debug.PrintStack()
-                }
-        }()
+	defer func() {
+		if err := recover(); err != nil {
+			log.Println("door.Close FAILURE:", err)
+			// This displays stack trace stderr
+			debug.PrintStack()
+		}
+	}()
 
 	log.Println("Closing...")
 	d.closeChannel <- true
-	if ! d.Disconnect() {
-		// log.Println("close write channel")
-		// close(d.writerChannel)
-		log.Println("close read handle")
-		CloseReader(d.Config.Comm_handle)
-		log.Println("closed read handle")
-	}
 
-	// d.closeChannel <- true
-	// close(d.closeChannel)
+	// CloseReader(d.Config.Comm_handle)
+
 	log.Println("wg.Wait()")
 	d.wg.Wait()
 	log.Println("Closed.")

+ 9 - 5
door/door_linux.go

@@ -1,9 +1,13 @@
 package door
 
 func (d *Door) setupChannels() {
-	d.wg.Add(2)
-	go Reader2(d.Config.Comm_handle, d)
-	// go Reader(d.Config.Comm_handle, &d.readerChannel)
-	// go Writer(d.Config.Comm_handle, &d.writerChannel)
-	go Writer2(d.Config.Comm_handle, d)
+	if d.ReaderCanClose {
+		// Yes, expect Reader and Writer to stop
+		d.wg.Add(2)
+	} else {
+		// Default:  Only wait for the Writer to stop
+		d.wg.Add(1)
+	}
+	go Reader(d.Config.Comm_handle, d)
+	go Writer(d.Config.Comm_handle, d)
 }

+ 2 - 2
door/door_test.go

@@ -81,7 +81,7 @@ func TestReadDropFile(t *testing.T) {
 		panic("Cannot create temporary file")
 	}
 
-	// Remember to clean up the file afterwards
+	// Clean up the dropfile afterwards
 	defer os.Remove(tmpFile.Name())
 
 	dfc := DropfileConfig{2, 20, 1800, "Test BBSID", 1701, "Real Username", "Handle", 880, 28, 0, 12}
@@ -173,7 +173,7 @@ func TestDetectFail(t *testing.T) {
 		dfc.Security_level, dfc.Time_left, dfc.Emulation, dfc.Node))
 	tmpFile.Close()
 
-	d := Door{}
+	d := Door{ReaderCanClose: true}
 
 	// Because we're not the only one calling door.Init(), the
 	// door global variables might be from a previous test run.

+ 6 - 4
door/help_linux_test.go

@@ -5,20 +5,23 @@ import (
 	"os"
 )
 
-var fdmap map[uintptr] *os.File
+// Create a map of os.File.Fd() to *os.File
+var fdmap map[uintptr]*os.File
 
 func init() {
-	fdmap = make(map[uintptr] *os.File)
+	fdmap = make(map[uintptr]*os.File)
 }
 
 func socket_to_fd(socket net.Conn) int {
 	client_conn := socket.(*net.TCPConn)
-	// This creates a duplicate, but once closed -- the fd gets reused!
+	// This creates a duplicate fd, but once closed -- the fd gets reused!
 	client_file, _ := client_conn.File()
+	// Preserve the *os.File so it doesn't close
 	fdmap[client_file.Fd()] = client_file
 	return int(client_file.Fd())
 }
 
+// If we find the Fd in the map, close and delete it.
 func close_fd(fd int) {
 	var fd_uintptr uintptr = uintptr(fd)
 	file, ok := fdmap[fd_uintptr]
@@ -27,4 +30,3 @@ func close_fd(fd int) {
 		delete(fdmap, fd_uintptr)
 	}
 }
-

+ 10 - 5
door/input_linux.go

@@ -2,16 +2,18 @@ package door
 
 import (
 	"log"
-	"syscall"
 	"sync/atomic"
+	"syscall"
 )
 
-func Reader2(handle int, d *Door) {
+func Reader(handle int, d *Door) {
 	// I don't need the select anymore.  Let the read block.
 	// defer d.wg.Done()
 	defer func() {
 		log.Printf("~Reader2\n")
-		d.wg.Done()
+		if d.ReaderCanClose {
+			d.wg.Done()
+		}
 	}()
 	defer func() {
 		if err := recover(); err != nil {
@@ -25,7 +27,7 @@ func Reader2(handle int, d *Door) {
 		if err != nil {
 			log.Printf("Reader ERR: %#v\n", err)
 			close(d.readerChannel)
-			if ! d.Disconnect() {
+			if !d.Disconnect() {
 				log.Println("Reader close writerChannel")
 				// d.Disconnected = true
 				atomic.StoreInt32(&d.Disconnected, 1)
@@ -41,7 +43,7 @@ func Reader2(handle int, d *Door) {
 		} else {
 			log.Printf("READ FAILED %d\n", read)
 			close(d.readerChannel)
-			if ! d.Disconnect() {
+			if !d.Disconnect() {
 				log.Println("Reader close writerChannel")
 				// d.Disconnected = true
 				atomic.StoreInt32(&d.Disconnected, 1)
@@ -55,6 +57,7 @@ func Reader2(handle int, d *Door) {
 	}
 }
 
+/*
 func Reader(handle int, readerChannel *chan byte) {
 	// I don't need the select anymore.  Let the read block.
 	defer func() {
@@ -83,6 +86,7 @@ func Reader(handle int, readerChannel *chan byte) {
 	}
 }
 
+// This doesn't work.  Closing the handle does not unblock the syscall.Read above.
 func CloseReader(handle int) {
 	defer func() {
 		if err := recover(); err != nil {
@@ -92,3 +96,4 @@ func CloseReader(handle int) {
 
 	syscall.Close(handle)
 }
+*/

+ 1 - 1
door/input_test.go

@@ -41,7 +41,7 @@ func TestDoorInputConnection(t *testing.T) {
 		dfc.Security_level, dfc.Time_left, dfc.Emulation, dfc.Node))
 	tmpFile.Close()
 
-	d := Door{}
+	d := Door{ReaderCanClose: true}
 
 	// Because we're not the only one calling door.Init(), the
 	// door global variables might be from a previous test run.

+ 1 - 1
door/menu_test.go

@@ -79,7 +79,7 @@ func TestMenuConnection(t *testing.T) {
 		dfc.Security_level, dfc.Time_left, dfc.Emulation, dfc.Node))
 	tmpFile.Close()
 
-	d := Door{}
+	d := Door{ReaderCanClose: true}
 	// If I call d.Init() more then once flag complains about flag redefined.
 	// Reset flags
 	flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)

+ 8 - 9
door/write.go

@@ -128,21 +128,20 @@ ok == false
 writing to a closed channel is a panic.
 */
 
-
 // Write string to client.
 func (d *Door) Write(output string) {
 	if d.Disconnect() {
 		return
 	}
 
-        defer func() {
-                if err := recover(); err != nil {
-                        log.Println("Write FAILURE:", err)
-                        // Display error to user
-                        // This displays stack trace stderr
-                        // debug.PrintStack()
-                }
-        }()
+	defer func() {
+		if err := recover(); err != nil {
+			log.Println("Write FAILURE:", err)
+			// Display error to user
+			// This displays stack trace stderr
+			// debug.PrintStack()
+		}
+	}()
 
 	if d.Disconnect() {
 		return

+ 26 - 26
door/write_linux.go

@@ -3,45 +3,43 @@ package door
 import (
 	"log"
 	"strings"
-	"syscall"
 	"sync/atomic"
+	"syscall"
 )
 
 // https://go101.org/article/channel-closing.html
 
-// This will get renamed back to Writer, once I get
-// it working...
-func Writer2(handle int, d *Door) {
+func Writer(handle int, d *Door) {
 	log.Println("Writer2")
 	defer d.wg.Done()
 	for {
 		select {
-		case <- d.closeChannel:
-		close(d.writerChannel)
-		log.Println("~Writer2")
-		return
+		case <-d.closeChannel:
+			close(d.writerChannel)
+			log.Println("~Writer")
+			return
 		default:
 		}
 
 		select {
-                case <- d.closeChannel:
-		close(d.writerChannel)
-		log.Println("~Writer2")
-		return
+		case <-d.closeChannel:
+			close(d.writerChannel)
+			log.Println("~Writer")
+			return
 		case output, ok := <-d.writerChannel:
 			if !ok {
 				log.Println("closeChannel")
-				if ! d.Disconnect() {
-				// d.Disconnected = true
-				atomic.StoreInt32(&d.Disconnected, 1)
-				// if !ok, the channel is already closed...
-				// close(d.writerChannel)
-}
-				log.Println("~Writer2")
+				if !d.Disconnect() {
+					// d.Disconnected = true
+					atomic.StoreInt32(&d.Disconnected, 1)
+					// if !ok, the channel is already closed...
+					// close(d.writerChannel)
+				}
+				log.Println("~Writer")
 				return
 
-//				d.closeChannel <- true
-//				continue
+				//				d.closeChannel <- true
+				//				continue
 			} else {
 				// log.Println("output")
 				/* Handle cases where we're updating a portion of the screen.
@@ -58,12 +56,12 @@ func Writer2(handle int, d *Door) {
 				n, err := syscall.Write(handle, buffer)
 				if (err != nil) || (n != len(buffer)) {
 					log.Println("closeChannel")
-					if ! d.Disconnect() {
-					// d.Disconnected = true
-					atomic.StoreInt32(&d.Disconnected, 1)
-					close(d.writerChannel)
+					if !d.Disconnect() {
+						// d.Disconnected = true
+						atomic.StoreInt32(&d.Disconnected, 1)
+						close(d.writerChannel)
 					}
-					log.Println("~Writer2")
+					log.Println("~Writer")
 					return
 				}
 			}
@@ -71,6 +69,7 @@ func Writer2(handle int, d *Door) {
 	}
 }
 
+/*
 func Writer(handle int, writerChannel *chan string) {
 	for output := range *writerChannel {
 		buffer := []byte(output)
@@ -81,3 +80,4 @@ func Writer(handle int, writerChannel *chan string) {
 		}
 	}
 }
+*/

+ 1 - 1
testdoor/testdoor.go

@@ -525,7 +525,7 @@ func main() {
 		}
 	}()
 
-	// defer d.Close()
+	defer d.Close()
 	ticker := time.NewTicker(time.Second)
 
 	go func() {