big changes to ClientManager, separate goroutine to handle cleanup of old Clients
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
This commit is contained in:
parent
242343ddac
commit
a11a718c4f
21
client.go
21
client.go
@ -11,18 +11,21 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ClientMsg int
|
||||
/* unused for now */
|
||||
|
||||
type Client struct {
|
||||
Message chan ClientMsg
|
||||
Socket net.Conn
|
||||
}
|
||||
|
||||
const (
|
||||
GopherMapFile = "/gophermap"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
Cmd chan Command
|
||||
Socket net.Conn
|
||||
}
|
||||
|
||||
func (client *Client) Init(conn *net.Conn) {
|
||||
client.Cmd = make(chan Command)
|
||||
client.Socket = *conn
|
||||
client.Message = make(chan ClientMsg)
|
||||
client.Socket = *conn
|
||||
}
|
||||
|
||||
func (client *Client) Start() {
|
||||
@ -30,7 +33,7 @@ func (client *Client) Start() {
|
||||
defer func() {
|
||||
/* Close-up shop */
|
||||
client.Socket.Close()
|
||||
close(client.Cmd)
|
||||
close(client.Message)
|
||||
}()
|
||||
|
||||
var count int
|
||||
@ -88,7 +91,7 @@ func (client *Client) SendError(format string, args ...interface{}) {
|
||||
|
||||
/* Format error message and append to response */
|
||||
message := fmt.Sprintf(format, args...)
|
||||
response = append(response, []byte(message)...)
|
||||
response = append(response, []byte(message + CrLf)...)
|
||||
response = append(response, []byte(LastLine)...)
|
||||
|
||||
/* We're sending an error, if this fails then fuck it lol */
|
||||
|
55
gophor.go
55
gophor.go
@ -57,7 +57,7 @@ var (
|
||||
ServerPort = flag.Int("port", 70, "server listening port")
|
||||
ServerHostname = flag.String("hostname", "127.0.0.1", "server hostname")
|
||||
ServerUid = flag.Int("uid", 1000, "UID to run server under")
|
||||
ServerGid = flag.Int("gid", 1000, "GID to run server under")
|
||||
ServerGid = flag.Int("gid", 100, "GID to run server under")
|
||||
UseChroot = flag.Bool("use-chroot", true, "chroot into the server directory")
|
||||
)
|
||||
|
||||
@ -87,59 +87,36 @@ func main() {
|
||||
/* Set privileges, see function definition for better explanation */
|
||||
setPrivileges()
|
||||
|
||||
/* Setup client manager */
|
||||
/* Setup manager */
|
||||
manager := new(ClientManager)
|
||||
manager.Init()
|
||||
manager.Start()
|
||||
|
||||
/* Handle signals so we can _actually_ shutdown */
|
||||
signals := make(chan os.Signal)
|
||||
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
|
||||
/* Handle signals so we can _actually_ shutdowm */
|
||||
signal.Notify(manager.Signals, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
/* Start the manager */
|
||||
manager.Start()
|
||||
|
||||
/* listener.Accept() server loop, in its own go-routine */
|
||||
go func() {
|
||||
count := 0
|
||||
for {
|
||||
newConn, err := listener.Accept()
|
||||
if err != nil {
|
||||
log.Fatalf("Error accepting connection: %s\n", err.Error())
|
||||
}
|
||||
|
||||
/* Create Client from newConn and register with the manager */
|
||||
client := new(Client)
|
||||
client.Init(&newConn)
|
||||
manager.Register<-client // this starts the Client go-routine
|
||||
|
||||
/* Every 'NewConnsBeforeClean' connections, request that manager perform clean */
|
||||
if count == NewConnsBeforeClean {
|
||||
manager.Cmd<-Clean
|
||||
count = 0
|
||||
} else {
|
||||
count += 1
|
||||
}
|
||||
go func() {
|
||||
/* Create Client from newConn and register with the manager */
|
||||
client := new(Client)
|
||||
client.Init(&newConn)
|
||||
manager.Register<-client
|
||||
}()
|
||||
}
|
||||
}()
|
||||
|
||||
/* Main thread sits and listens for OS signals */
|
||||
for {
|
||||
sig := <-signals
|
||||
log.Printf("Received signal %v, waiting to finish up... (hit CTRL-C to terminate without cleanup)\n", sig)
|
||||
|
||||
for {
|
||||
select {
|
||||
case manager.Cmd<-Stop:
|
||||
/* wait on clean */
|
||||
log.Printf("Clean-up finished, exiting now...\n")
|
||||
os.Exit(0)
|
||||
|
||||
case sig = <-signals:
|
||||
if sig == syscall.SIGTERM {
|
||||
log.Fatalf("Stopping NOW.\n")
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
/* When manager message channel closes, we all done */
|
||||
<-manager.Message
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func enterServerDir() {
|
||||
|
132
manager.go
132
manager.go
@ -1,59 +1,121 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"log"
|
||||
"time"
|
||||
// "syscall"
|
||||
)
|
||||
|
||||
type ManagerMsg int
|
||||
const (
|
||||
/* FROM manager */
|
||||
Done ManagerMsg = iota
|
||||
|
||||
/* TO manager */
|
||||
RemoveOld ManagerMsg = iota
|
||||
|
||||
/* Internal */
|
||||
FinishUp ManagerMsg = iota
|
||||
)
|
||||
|
||||
type ClientManager struct {
|
||||
Cmd chan Command
|
||||
Clients map[*Client]bool
|
||||
Register chan *Client
|
||||
Unregister chan *Client
|
||||
Signals chan os.Signal // OS sends, manager receives
|
||||
Register chan *Client // User sends, manager receives
|
||||
Message chan ManagerMsg // User and manager, send / receive
|
||||
SleepTime time.Duration
|
||||
}
|
||||
|
||||
func (manager *ClientManager) Init() {
|
||||
manager.Cmd = make(chan Command)
|
||||
manager.Clients = make(map[*Client]bool)
|
||||
manager.Signals = make(chan os.Signal)
|
||||
manager.Register = make(chan *Client)
|
||||
manager.Unregister = make(chan *Client)
|
||||
manager.Message = make(chan ManagerMsg)
|
||||
manager.SleepTime = time.Second
|
||||
}
|
||||
|
||||
func (manager *ClientManager) Start() {
|
||||
/* Internal channel to stop cleaner goroutine */
|
||||
cleanup := make(chan bool)
|
||||
|
||||
/* Main manager goroutine */
|
||||
go func() {
|
||||
defer func() {
|
||||
/* We should have exited before this, but :shrug: */
|
||||
close(manager.Register)
|
||||
close(manager.Signals)
|
||||
close(manager.Message)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case cmd := <-manager.Cmd:
|
||||
/* Received manager command, handle! */
|
||||
switch cmd {
|
||||
case Stop:
|
||||
/* Stop and delete all clients, then return */
|
||||
for client := range manager.Clients {
|
||||
client.Cmd<-Stop
|
||||
delete(manager.Clients, client)
|
||||
}
|
||||
return
|
||||
|
||||
case Clean:
|
||||
/* Delete all 'done' clients */
|
||||
for client := range manager.Clients {
|
||||
select {
|
||||
case <-client.Cmd:
|
||||
/* Channel closed, client done, delete! */
|
||||
delete(manager.Clients, client)
|
||||
default:
|
||||
/* Don't lock :) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* New client received */
|
||||
case client := <-manager.Register:
|
||||
/* Received new client to register */
|
||||
/* TODO: decrease SleepTime for when more connections added */
|
||||
manager.Clients[client] = true
|
||||
client.Start()
|
||||
|
||||
case client := <-manager.Unregister:
|
||||
/* Received client id to unregister */
|
||||
if _, ok := manager.Clients[client]; ok {
|
||||
client.Cmd<-Stop
|
||||
delete(manager.Clients, client)
|
||||
/* Message receieved */
|
||||
case msg := <-manager.Message:
|
||||
switch msg {
|
||||
default:
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/* OS signal received */
|
||||
case sig := <-manager.Signals:
|
||||
log.Printf("SIGNAL RECEIVED: %v\n", sig)
|
||||
log.Printf("Received %v, waiting on cleanup before exit... (ctrl-c again to stop NOW)\n", sig)
|
||||
cleanup<-true
|
||||
select {
|
||||
case sig = <-manager.Signals:
|
||||
log.Printf("Signal received again, exiting now.\n")
|
||||
return
|
||||
case <-cleanup:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
/* Start cleaner goroutine in background */
|
||||
go manager.Cleaner(cleanup)
|
||||
}
|
||||
|
||||
func (manager *ClientManager) Cleaner(cleanup chan bool) {
|
||||
finishUp := false
|
||||
for {
|
||||
/* Check for cleanup signal */
|
||||
select {
|
||||
case _ = <-cleanup:
|
||||
finishUp = true
|
||||
default:
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
for client := range manager.Clients {
|
||||
select {
|
||||
case <-client.Message:
|
||||
delete(manager.Clients, client)
|
||||
default:
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
|
||||
if finishUp {
|
||||
break
|
||||
} else {
|
||||
time.Sleep(manager.SleepTime)
|
||||
}
|
||||
}
|
||||
|
||||
/* Final cleanup */
|
||||
for client := range manager.Clients {
|
||||
<-client.Message
|
||||
delete(manager.Clients, client)
|
||||
}
|
||||
|
||||
/* Close the cleanup channel -- indicates we're done! */
|
||||
close(cleanup)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user