package main import ( "crypto/tls" "encoding/binary" "flag" "fmt" "log" "net" "os" ) var ( port = flag.Int("port", 8000, "port to listen on") certPath = flag.String("cert", "", "path to cert file") keyPath = flag.String("key", "", "path to key file") ) type wrappedConn struct { *net.TCPConn } func (conn *wrappedConn) Close() error { // If you call close() on a socket that has outstanding data in the recv // buffer, then the TCP stack on some OSes will send a RST instead of a FIN. // To avoid this behavior, we must call shutdown(fd, SHUT_WR) on the socket // first before closing it. conn.TCPConn.CloseWrite() return conn.TCPConn.Close() } func main() { flag.Parse() logger := log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lmicroseconds) addr := fmt.Sprint(":", *port) ln, err := net.Listen("tcp", addr) var hasCert bool var cert tls.Certificate if len(*certPath) != 0 && len(*keyPath) != 0 { cert, err = tls.LoadX509KeyPair(*certPath, *keyPath) hasCert = true } if err != nil { logger.Fatalln("listen error: ", err.Error()) } defer ln.Close() for { var tcpConn *net.TCPConn conn, err := ln.Accept() var ok bool if tcpConn, ok = conn.(*net.TCPConn); !ok { logger.Printf("couldn't case %v to *net.TCPConn\n", conn) } else { conn = &wrappedConn{tcpConn} } if err == nil && hasCert { tlsConn := tls.Server(conn, &tls.Config{ Certificates: []tls.Certificate{cert}, }) err = tlsConn.Handshake() conn = tlsConn } if err != nil { logger.Println("accept error: ", err.Error()) continue } go handleConnection(conn, logger) } } func handleConnection(conn net.Conn, logger *log.Logger) { defer conn.Close() for { var value uint32 if err := binary.Read(conn, binary.LittleEndian, &value); err != nil { logger.Println(conn.RemoteAddr().String, " read error: ", err.Error()) break } else { if value%128 == 0 { logger.Println(conn.RemoteAddr().String(), " read value: ", value) } if value == 2048 { if err := binary.Write(conn, binary.LittleEndian, &value); err != nil { logger.Println(conn.RemoteAddr().String(), " write error just before closing: ", err.Error()) } break } } } return }