Hi,

I’m trying to get an https server working by overwriting the 
accept/read/write methods in the http module. I’m using go-wolfssl for TLS.

The server will accept a TLS 1.2 connection, then send some random data to 
the client connects, then wait for another connection.

The issue that I’m seeing is that whenever the server sends large payloads, 
it’ll do that successfully but it then can’t send data to the next client 
that connects (the send errors out with the TCP error EBADF). If dealing 
with smaller payloads (<30k), the server can send data successfully to each 
client that connects. Then as soon as a large one is sent, the next 
transmission fails.

If I disable the GOGC with debug.SetGCPercent(-1), the issue goes away and 
I can send as many large payloads as required. From the debugging I’ve done 
so far, this looks like an issue with the GO garbage collector dropping C 
pointers. go-wolfssl relies on the wolfSSL C library so it uses CGO. Does 
anyone have any other ideas or input?

Code is below. See this repo to actually run it GitHub - 
lealem47/go-wolfssl-https-server  
<https://github.com/lealem47/go-wolfssl-https-server/>

Thank you!


```

package main import ( "bytes" "crypto/rand" "encoding/base64" "fmt" log 
"github.com/sirupsen/logrus" wolfSSL "github.com/wolfssl/go-wolfssl" "net" 
"net/http" "os" "strconv" "sync" "time" ) const defaultPort = "8443" type 
wolfSSLListener struct { listener net.Listener ctx *wolfSSL.WOLFSSL_CTX } 
// Accept waits for and returns the next connection to the listener. func 
(cl *wolfSSLListener) Accept() (net.Conn, error) { conn, err := 
cl.listener.Accept() if err != nil { return nil, err } 
fmt.Println("Accepted new connection from:", conn.RemoteAddr()) ssl := 
wolfSSL.WolfSSL_new(cl.ctx) if ssl == nil { fmt.Println("WolfSSL_new 
Failed") os.Exit(1) } file, err := conn.(*net.TCPConn).File() if err != nil 
{ panic(err) } fd := file.Fd() wolfSSL.WolfSSL_set_fd(ssl, int(fd)) ret := 
wolfSSL.WolfSSL_accept(ssl) if ret != wolfSSL.WOLFSSL_SUCCESS { 
fmt.Println("WolfSSL_accept error ", ret) } else { fmt.Println("Client 
Successfully Connected!") } return &wolfSSLConn{ conn: conn, ssl: ssl, }, 
nil } // Close closes the listener, making it stop accepting new 
connections. func (cl *wolfSSLListener) Close() error { 
fmt.Println("Closing listener...") return cl.listener.Close() } // Addr 
returns the listener's network address. func (cl *wolfSSLListener) Addr() 
net.Addr { return cl.listener.Addr() } type wolfSSLConn struct { conn 
net.Conn ssl *wolfSSL.WOLFSSL buffer bytes.Buffer mu sync.Mutex closed bool 
} func (w *wolfSSLConn) Read(b []byte) (int, error) { log.Infof("Calling 
read: %d", len(b)) ret := wolfSSL.WolfSSL_read(w.ssl, b, uintptr(len(b))) 
if ret < 0 { errCode := wolfSSL.WolfSSL_get_error(w.ssl, int(ret)) return 
0, fmt.Errorf("read error: %d", errCode) } log.Infof("Read bytes: %s", 
string(b[:ret])) return int(ret), nil } func (w *wolfSSLConn) Write(b 
[]byte) (int, error) { log.Infof("Calling write: %d", len(b)) sz := 
uintptr(len(b)) ret := wolfSSL.WolfSSL_write(w.ssl, b, sz) if ret < 0 { 
errCode := wolfSSL.WolfSSL_get_error(w.ssl, int(ret)) return 0, 
fmt.Errorf("write error: %d", errCode) } return int(ret), nil } func (w 
*wolfSSLConn) Close() error { log.Infof("Closing connection") 
wolfSSL.WolfSSL_shutdown(w.ssl) wolfSSL.WolfSSL_free(w.ssl) return 
w.conn.Close() } func (w *wolfSSLConn) LocalAddr() net.Addr { return 
w.conn.LocalAddr() } func (w *wolfSSLConn) RemoteAddr() net.Addr { return 
w.conn.RemoteAddr() } func (w *wolfSSLConn) SetDeadline(t time.Time) error 
{ return w.conn.SetDeadline(t) } func (w *wolfSSLConn) SetReadDeadline(t 
time.Time) error { return w.conn.SetReadDeadline(t) } func (w *wolfSSLConn) 
SetWriteDeadline(t time.Time) error { return w.conn.SetWriteDeadline(t) } 
// Handler for generating and base64 encoding 5KB of random data func 
randomDataHandler(w http.ResponseWriter, r *http.Request) { // Get the 
"size" query parameter from the request sizeParam := 
r.URL.Query().Get("size") size := 500000 // default size // If the "size" 
parameter is provided, convert it to an integer if sizeParam != "" { 
parsedSize, err := strconv.Atoi(sizeParam) if err != nil || parsedSize <= 0 
{ http.Error(w, "Invalid size parameter", http.StatusBadRequest) return } 
size = parsedSize } // Generate random data of the specified size data := 
make([]byte, size) _, err := rand.Read(data) if err != nil { http.Error(w, 
"Could not generate random data", http.StatusInternalServerError) return } 
// Base64 encode the random data encodedData := 
base64.StdEncoding.EncodeToString(data) // Set content type and write the 
base64 encoded data w.Header().Set("Content-Type", "application/base64") 
w.Write([]byte(encodedData)) } func main() { port := defaultPort // Set 
logging level log.SetLevel(log.InfoLevel) 
log.SetFormatter(&log.TextFormatter{ DisableColors: false, FullTimestamp: 
true, }) // Set up the HTTP server and routes http.HandleFunc("/", 
randomDataHandler) CERT_FILE := "./certs/server-cert.pem" KEY_FILE := 
"./certs/server-key.pem" /* Initialize wolfSSL */ wolfSSL.WolfSSL_Init() /* 
Create WOLFSSL_CTX with tlsv12 */ ctx := 
wolfSSL.WolfSSL_CTX_new(wolfSSL.WolfTLSv1_2_server_method()) if ctx == nil 
{ fmt.Println(" WolfSSL_CTX_new Failed") os.Exit(1) } /* Load server 
certificates into WOLFSSL_CTX */ ret := 
wolfSSL.WolfSSL_CTX_use_certificate_file(ctx, CERT_FILE, 
wolfSSL.SSL_FILETYPE_PEM) if ret != wolfSSL.WOLFSSL_SUCCESS { 
fmt.Println("Error: WolfSSL_CTX_use_certificate Failed") os.Exit(1) } /* 
Load server key into WOLFSSL_CTX */ ret = 
wolfSSL.WolfSSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, 
wolfSSL.SSL_FILETYPE_PEM) if ret != wolfSSL.WOLFSSL_SUCCESS { 
fmt.Println("Error: WolfSSL_CTX_use_PrivateKey Failed") os.Exit(1) } 
baseListener, err := net.Listen("tcp", ":"+port) if err != nil { 
fmt.Println("Error starting listener:", err) return } defer 
baseListener.Close() wolfSSLListener := &wolfSSLListener{ listener: 
baseListener, ctx: ctx, } log.Printf("Server listening on 
https://localhost:%s";, port) err = http.Serve(wolfSSLListener, nil) if err 
!= nil { fmt.Println("Error starting HTTP server:", err) } }

```

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/a662824b-3555-4143-bfd8-b3431b7dc942n%40googlegroups.com.

Reply via email to