diff --git a/emaild/server.go b/emaild/server.go index 93becc2..14da621 100644 --- a/emaild/server.go +++ b/emaild/server.go @@ -12,18 +12,11 @@ import "math/rand" import "net" import "time" import "log" +import "bufio" +import "strings" +import "strconv" -// will try to get this hosts FQDN -// import "github.com/Showmax/go-fqdn" - -// this is the king of dns libraries -// import "github.com/miekg/dns" - -// this is awesome for debugging -// import "github.com/davecgh/go-spew/spew" - -// this is our dnssec IPv6 socket library -import "git.wit.com/jcarr/dnssecsocket" +import "github.com/davecgh/go-spew/spew" const ( CONN_HOST = "localhost" @@ -32,12 +25,18 @@ const ( ) /* +// the simplest handler of them all +// just write everything from the socket to stdout go func(c net.Conn) { defer c.Close() io.Copy(os.Stdout, c) }(conn) */ +func random() int { + return rand.Intn(50) + 4 +} + func main() { /* // redirect all this output to systemd @@ -83,6 +82,58 @@ func main() { log.Println("Accepted new connection from: " + conn.RemoteAddr().String()) // Handle connections in a new goroutine. - go dnssecsocket.HandleConnection(conn) + go HandleConnection(conn) + } +} + +// +// Handle each connection +// Each client must send it's hostname as the first line +// Then each hostname is verified with DNSSEC +// +func HandleConnection(conn *net.TCPConn) { + ipv6client := conn.RemoteAddr() + log.Println("Serving to %s as the IPv6 client", ipv6client) + + // setup this TCP socket as the "standard input" + // newStdin, _ := bufio.NewReader(conn.File()) + newStdin, _ := conn.File() + newreader := bufio.NewReader(newStdin) + + log.Println("Waiting for the client to tell me its name") + netData, err := newreader.ReadString('\n') + spew.Dump(netData) + if err != nil { + log.Println(err) + return + } + + // f, _ := conn.File() + + for { + defer conn.Close() + netData, err := newreader.ReadString('\n') + if err != nil { + log.Println(err) + return + } + + temp := strings.TrimSpace(string(netData)) + if temp == "STOP" { + break + } + log.Println("Recieved: ", temp) + + if (temp == "list") { + log.Println("Should run list here") + } + + if (temp == "cpuinfo") { + log.Println("Should cat /proc/cpuinfo") + } + + result := strconv.Itoa(random()) + "\n" + conn.Write([]byte(string(result))) + return } } diff --git a/emaild/test2.go b/emaild/test2.go new file mode 100644 index 0000000..9b90b58 --- /dev/null +++ b/emaild/test2.go @@ -0,0 +1,129 @@ +package main + +import ( + "context" + "flag" + "fmt" + "log" + "net/http" + "os" + "os/signal" + "sync/atomic" + "time" +) + +type key int + +const ( + requestIDKey key = 0 +) + +var ( + listenAddr string + healthy int32 +) + +func main() { + flag.StringVar(&listenAddr, "listen-addr", ":5000", "server listen address") + flag.Parse() + + logger := log.New(os.Stdout, "http: ", log.LstdFlags) + logger.Println("Server is starting...") + + router := http.NewServeMux() + router.Handle("/", index()) + router.Handle("/healthz", healthz()) + + nextRequestID := func() string { + return fmt.Sprintf("%d", time.Now().UnixNano()) + } + + server := &http.Server{ + Addr: listenAddr, + Handler: tracing(nextRequestID)(logging(logger)(router)), + ErrorLog: logger, + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 15 * time.Second, + } + + done := make(chan bool) + quit := make(chan os.Signal, 1) + signal.Notify(quit, os.Interrupt) + + go func() { + <-quit + logger.Println("Server is shutting down...") + atomic.StoreInt32(&healthy, 0) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + server.SetKeepAlivesEnabled(false) + if err := server.Shutdown(ctx); err != nil { + logger.Fatalf("Could not gracefully shutdown the server: %v\n", err) + } + close(done) + }() + + logger.Println("Server is ready to handle requests at", listenAddr) + atomic.StoreInt32(&healthy, 1) + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + logger.Fatalf("Could not listen on %s: %v\n", listenAddr, err) + } + + <-done + logger.Println("Server stopped") +} + +func index() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + return + } + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("X-Content-Type-Options", "nosniff") + w.WriteHeader(http.StatusOK) + fmt.Fprintln(w, "Hello, World!") + }) +} + +func healthz() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if atomic.LoadInt32(&healthy) == 1 { + w.WriteHeader(http.StatusNoContent) + return + } + w.WriteHeader(http.StatusServiceUnavailable) + }) +} + +func logging(logger *log.Logger) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer func() { + requestID, ok := r.Context().Value(requestIDKey).(string) + if !ok { + requestID = "unknown" + } + logger.Println(requestID, r.Method, r.URL.Path, r.RemoteAddr, r.UserAgent()) + }() + next.ServeHTTP(w, r) + }) + } +} + +func tracing(nextRequestID func() string) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + requestID := r.Header.Get("X-Request-Id") + if requestID == "" { + requestID = nextRequestID() + } + ctx := context.WithValue(r.Context(), requestIDKey, requestID) + w.Header().Set("X-Request-Id", requestID) + next.ServeHTTP(w, r.WithContext(ctx)) + }) + } +}