TLS connection cannot be used after timeout of "SetDealine"

85 views
Skip to first unread message

pet...@gmx.net

unread,
Jan 14, 2020, 8:43:32 AM1/14/20
to golang-nuts
Hi Gophers,

I have client code which test network transfer performance per second.

For that I use "conn.SetDeadline(time.Second)".
The performance testing is performed in a loop ot 5 rounds where each round sets a "SetDeadline" and then d a io.Copy/ZeroReader to the server and count the transfered bytes.

This works perfectly with a normal NON-TLS connection to a server. 
After each Timeout because of "SetDeadline" the NON-TLS connection is still valid and can be reused.

However, if I do the same with a TLS connection then after the first "SetDeadline" and timeout the connection is somehow broken and cannot be used anymore for further io.Copy's.

Here is some test code which tests 5 rounds of SetDeadline/ at 1st with a standard conneciton and then with TLS connection.
With the TLS connection it breaks and 0 bytes are transfered all the time.

Looking for help :-)

Thanks - Marcel.

package main

import (
       
"context"
       
"crypto/rand"
       
"crypto/tls"
       
"encoding/hex"
       
"io"
       
"io/ioutil"
       
"log"
       
"net"
       
"time"
)

const (
        ciddr    
= ":5000"
        keyInHex
= "2d2d2d2d2d424547494e2050524956415445204b45592d2d2d2d2d0d0a4d494945764149424144414e42676b71686b6947397730424151454641415343424b59776767536941674541416f49424151444f4259315353616b386c7955530d0a384f597252477334314b7456554c647439516e71597169555636465a4e4b764f7a6c56717274506e76355a564d4a5462334d75326a4f2f54694b32366b5647440d0a2f584b61436b564e6b7647687a4e514736467a426a4d67734d72616f5a59472f49523744333663724847344553717251713645326647706c4766716d526643370d0a4c53744f487a364a4f476250715670346c645a546d70335334565857786a73326e4a4d3637576d577061436975566351376a703976576f50325657664659426a0d0a447a49547633574d6f477451466c42614947307934395a68626e32793056414e304c4b6c4775476244386b6543764a66372b65414b5a6a7668746364612b586b0d0a72496d4e51544a4d4f624c2b6e5455305a7771666a4574754c46736336696a306f5278384543584475585a73537731536b784e4c4d494576315843577531434d0d0a31447042626b4b2f41674d4241414543676745414555596e356b6c6b316a363644672b437a5166736b5a524c56566a794f46622b594e6571324e314d477757750d0a6a6957417866516f73" +
               
"6c712f43522b4d7136366b716762424b525268744b33776a73655762314944493544356a35357a2f4b7849387257534a78714e6443736d0d0a714e626e464864524e6530705546544f593761775372673931344a4a494e336d5a4674534d5465766236503641746c7053346b4d736d2f5a596441672b5750350d0a422f663177736b69356944684d582f3364773532454830574d5743554e3256414a2f696d316e365732616e6c3054494f4a69774d30336a732b767a61367048650d0a59443347345366702f5a53303573576f2f7846796677384245565673655535736d70545852775379544f484d763178714835584c4f4b367845615173386c42560d0a4b6b77676f794849364c334b6975756d6a45396656667a6a5a686968682f443241616570753262446d514b426751447a2b4e3662476e73693468744f3347394a0d0a36743870776d39475565346f764f367131377132396f726d31426751322f516462674c785641417442336436544939586b566c516f744a58756562537a3674510d0a66763971674d6c6b5a6552413965367a49416668553457526b5270557448584c3047476875583546696954363532316b456f657833726b6747417437593353670d0a2b314749645a3474774252616b536434474b7556775a514d41774b42675144594c626464797735455553486178596c" +
               
"5275593874477945616f726a564e4e4c440d0a6d5030374748726a6c343970697a4e54775a493770666833466c4f36504a3544664d6b4c7231487853416f394151376f44585470506e716457433637544279670d0a50387a325544434164786d442b4d4872766b2f7070536c356a5944394f3839777133417166326b7767634f35554150484a47367a304a4f45366477482b4f48350d0a79437747684755586c514b426748516a767553624949386b6a39646b7646323176334b447172455241347a46452b436b5062416e6755774e487a2b33565768460d0a48495742645776364a2f684352654a72774e6251433833544933797265325167634c706b674871597671586c375447385238514f484947465438474f2f7078390d0a6f4678366a772f506958636667455770524974352b5371384234732f64782f44513762774e744b556f35765269625a3047417038556c7539416f4741427554650d0a5669566c6e525168536b4c47634537456e43476a5771415a324f4c495865694247754e61392b736262626738754d305268736c794e516f4850596331584e32620d0a343732426c58704171565668546c4576693069737a4676466b622b4a6f69716d744b77312f384c4d6b344c5a5846564459795962506e3865762f537156754f410d0a766a6f313970414d31396f505a4d6871703131" +
               
"646476326d514c4c564d67774b4b324d4a666b6b43675942504243304b6579624736444964356d5a4a7056394b0d0a4238575a5663727945447a786f75486473517145686637666c355a7532467a38326b656d41686a616b3531554546525437674e596b4b414753673877507453610d0a75614c2f2b4c626174504d2b5a6c716a51417859354f3454392b4e56305875546d4644744f4c366765493054665374306a6179754e654b6c68374c63516c6e510d0a6270495853574c2b707850655a6858774e2b316972773d3d0d0a2d2d2d2d2d454e442050524956415445204b45592d2d2d2d2d0d0a"
        pemInHex
= "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0d0a4d4949432f6a434341656167417749424167494a414d774c783261574f386a414d413047435371475349623344514542437755414d425178456a415142674e560d0a42414d4d43577876593246736147397a64444165467730794d4441784d5451784d4441784d5442614677307a4d4441784d5445784d4441784d5442614d4251780d0a456a415142674e5642414d4d43577876593246736147397a64444343415349774451594a4b6f5a496876634e4151454242514144676745504144434341516f430d0a67674542414d34466a564a4a715479584a524c7735697445617a6a55713156517432333143657069714a52586f566b307138374f56577175302b652f6c6c55770d0a6c4e76637937614d37394f49726271525559503963706f4b525532533861484d3141626f584d474d794377797471686c6762386848735066707973636267524b0d0a717443726f545a38616d555a2b715a46384c73744b303466506f6b345a732b70576e6956316c4f616e644c68566462474f7a61636b7a7274615a616c6f4b4b350d0a567844754f6e323961672f5a565a385667474d504d684f2f645979676131415755466f6762544c6a316d467566624c525541335173715561345a73507952344b0d0a386c2f76353441706d" +
               
"4f2b473178317235655373695931424d6b7735737636644e54526e43702b4d5332347357787a714b505368484877514a634f35646d784c0d0a44564b544530737767532f56634a613755497a554f6b4675517238434177454141614e544d464577485159445652304f424259454641315370783369486e394e0d0a66557463655343494f55376d334c71664d42384741315564497751594d4261414641315370783369486e394e66557463655343494f55376d334c71664d4138470d0a41315564457745422f7751464d414d42416638774451594a4b6f5a496876634e4151454c4251414467674542414445786864464a724a6469576d3551303067710d0a74706876754869634664315864516b613851764a6e323736354e706a624d776b4f67494f706d32644d376e467063784d4a5a77546875317062515864653071570d0a4f415979593274654b7344507a302b48496c755a49737336697a5852732f2b4a43312b2b6a4a34673746316d64556a64517a7733506957316b72516d2f5746430d0a624d34544c656f3158464b4c42696678674170346f532f317a37674478545962336f764c7a415243637857345571726a384b7036467474616c78326c4c3566470d0a6f307a452b4358746d4756636546316e427050685737366430614435487a56316931497055384b6f5674344a673043" +
               
"524176714139556835673279434d3531550d0a5762766a564934526b474c4a6d5761796d4269572b52526f3465766c347679353650356744526b766574464e3443444e41327a412f71307762653654516759350d0a5479493d0d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0d0a"
)

type
ZeroReader struct {
}

func
NewZeroReader() *ZeroReader {
       
return &ZeroReader{}
}

func
(this ZeroReader) Read(p []byte) (n int, err error) {
       
for i := range p {
                p
[i] = 0
       
}

       
return len(p), nil
}

func hexToBuffer
(txt string) ([]byte, error) {
        ba
, err := hex.DecodeString(txt)
       
if err != nil {
                log
.Println(err)
               
return nil, err
       
}

       
return ba, nil
}

func newTlsConfig
() (*tls.Config, error) {
        key
, err := hexToBuffer(keyInHex)
       
if err != nil {
                log
.Println(err)
               
return nil, err
       
}

        pem
, err := hexToBuffer(pemInHex)
       
if err != nil {
                log
.Println(err)
               
return nil, err
       
}

        certificate
, err := tls.X509KeyPair(pem, key)
       
if err != nil {
                log
.Println(err)
               
return nil, err
       
}

        tlsConfig
:= &tls.Config{Certificates: []tls.Certificate{certificate}}
        tlsConfig
.Rand = rand.Reader

       
return tlsConfig, nil
}

func
NewServer(ctx context.Context, useTls bool) error {
       
var conn net.Conn

       
if useTls {
                tlsConfig
, err := newTlsConfig()

                log
.Printf("TLS server: listen")
                ln
, err := tls.Listen("tcp", ciddr, tlsConfig)
               
if err != nil {
                        log
.Println(err)
                       
return err
               
}
                defer func
() {
                        err
:= ln.Close()
                       
if err != nil {
                                log
.Println(err)
                       
}
               
}()

                log
.Printf("TLS server: listen accept ...")
                conn
, err = ln.Accept()
               
if err != nil {
                        log
.Println(err)
                       
return err
               
}
       
} else {
                log
.Printf("server: listen")
                ln
, err := net.Listen("tcp", ciddr)
               
if err != nil {
                        log
.Println(err)
                       
return err
               
}
                defer func
() {
                        err
:= ln.Close()
                       
if err != nil {
                                log
.Println(err)
                       
}
               
}()

                log
.Printf("server: listen accept ...")
                conn
, err = ln.Accept()
               
if err != nil {
                        log
.Println(err)
                       
return err
               
}
       
}

       
select {
       
case <-ctx.Done():
                err
:= conn.Close()
               
if err != nil {
                        log
.Println(err)
                       
return err
               
}
       
default:
                log
.Printf("server read and discard ...")

                n
,err := io.Copy(ioutil.Discard, conn)
               
if n > 0 {
                        log
.Printf("server bytes read: %d",n)

               
}
               
if err != nil {
                        log
.Println(err)
                       
return err
               
}
       
}

       
return nil
}

func main
() {
        useTls
:= false

       
for {
                log
.Printf("--------------------------------")
                log
.Printf("Test with TLS = %v",useTls)

                ctx
,cancel := context.WithCancel(context.Background())

                go func
() {
                        err
:= NewServer(ctx,useTls)
                       
if err != nil {
                                log
.Println(err)
                                panic
(err)
                       
}
               
}()

                log
.Printf("Give server time to startup ...")
                time
.Sleep(time.Second)

               
var conn net.Conn

               
if useTls {
                       
var err error

                        config
:= &tls.Config{
                               
InsecureSkipVerify: true,
                       
}

                        log
.Printf("Dial TLS to server ... ")

                        conn
, err = tls.Dial("tcp", ciddr, config)
                       
if err != nil {
                                log
.Println(err)
                                panic
(err)
                       
}
               
} else {
                       
var err error

                        log
.Printf("Dial to server ... ")

                        conn
,err = net.Dial("tcp",ciddr)
                       
if err != nil {
                                log
.Println(err)
                                panic
(err)
                       
}
               
}

                log
.Printf("Connection established")

               
for i := 0; i < 5; i++ {
                        log
.Printf("loop %v: setDeadline",i)
                        conn
.SetDeadline(time.Now().Add(time.Second))

                        n
,err := io.Copy(conn,ZeroReader{})
                        log
.Printf("loop %v: bytes written: %d",i,n)
                       
if err != nil {
                                neterr
, ok := err.(net.Error)

                               
if !ok || neterr.Timeout() {
                                       
continue
                               
}
                                log
.Println(err)
                                panic
(err)
                       
}

               
}

                log
.Printf("Connection close")
                err
:= conn.Close()
               
if err != nil {
                        log
.Println(err)
                        panic
(err)
               
}

                log
.Printf("Kill server")
                cancel
()
                log
.Printf("Give server time to die ...")
                time
.Sleep(time.Second)

                log
.Printf("Server killed")

                useTls
= !useTls
       
}
}


My env:

set GO111MODULE=on
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\ogmpetav\AppData\Local\go-build
set GOENV=C:\Users\ogmpetav\AppData\Roaming\go\env
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\xxx\Documents\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=c:\go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=c:\go\pkg\tool\windows_amd64
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=D:\go\src\deadline\go.mod
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\xxx\AppData\Local\Temp\go-build505968610=/tmp/go-build -gno-record-gcc-switches



Guy Allard

unread,
Jan 21, 2020, 8:30:38 AM1/21/20
to golang-nuts
I hope you already figured this out......

The documentation for SetDeadline in the tls package specifically says:

 After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.

 

Reply all
Reply to author
Forward
0 new messages