commit 7643de5da53a48e8235ef62d63d5c7f0007537bb
parent d00ed1bef534f12831fa61cfface30544097d550
Author: Matsuda Kenji <info@mtkn.jp>
Date: Wed, 27 Dec 2023 15:29:46 +0900
change Server.Auth function
Diffstat:
| M | auth_test.go | | | 59 | ++++++++++++++++++++++++++++++----------------------------- |
| M | server.go | | | 18 | ++++++++++-------- |
| M | server2_test.go | | | 65 | ++++++++++++++++++++++++++++------------------------------------- |
3 files changed, 68 insertions(+), 74 deletions(-)
diff --git a/auth_test.go b/auth_test.go
@@ -9,9 +9,6 @@ import (
"git.mtkn.jp/lib9p/testfs"
)
-// TODO: this test sometimes fails.
-// err: unknown fid, or err: not authenticated.
-// maybe there is some race condition or something.
func TestAuth(t *testing.T) {
conn := testfs.SetupConn()
defer conn.Close()
@@ -23,33 +20,29 @@ func TestAuth(t *testing.T) {
asr.Close()
asw.Close()
}()
- conn.S.Auth = func(ctx context.Context, respc chan<- *lib9p.Req) chan<- *lib9p.Req {
- authc := make(chan *lib9p.Req)
- go func() {
- for {
- select {
- case <-ctx.Done():
+ conn.S.Auth = func(ctx context.Context, authc <-chan *lib9p.Req, respc chan<- *lib9p.Req) {
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case r, ok := <-authc:
+ if !ok {
return
- case r, ok := <-authc:
- if !ok {
- return
- }
- ifcall := r.Ifcall.(*lib9p.TAuth)
- aqid := lib9p.Qid{Type: lib9p.QTAUTH, Vers: 0, Path: ^uint64(0)}
- r.Afid.File = &lib9p.AuthFile{
- Qid: aqid,
- Uname: ifcall.Uname,
- Aname: ifcall.Aname,
- W: acw,
- R: acr,
- }
- runAuth(ctx, t, r.Afid.File.(*lib9p.AuthFile), asr, asw)
- r.Ofcall = &lib9p.RAuth{Tag: ifcall.Tag, Aqid: aqid}
- respc <- r
}
+ ifcall := r.Ifcall.(*lib9p.TAuth)
+ aqid := lib9p.Qid{Type: lib9p.QTAUTH, Vers: 0, Path: ^uint64(0)}
+ r.Afid.File = &lib9p.AuthFile{
+ Qid: aqid,
+ Uname: ifcall.Uname,
+ Aname: ifcall.Aname,
+ W: acw,
+ R: acr,
+ }
+ runAuth(ctx, t, r.Afid.File.(*lib9p.AuthFile), asr, asw)
+ r.Ofcall = &lib9p.RAuth{Tag: ifcall.Tag, Aqid: aqid}
+ respc <- r
}
- }()
- return authc
+ }
}
ctx := context.Background()
_, _, err := conn.C.Version(ctx, lib9p.NOTAG, 8*1024, "9P2000")
@@ -111,12 +104,20 @@ func runAuth(ctx context.Context, t *testing.T, afile *lib9p.AuthFile, r io.Read
}
case 1: // accepted
afile.AuthOK = true
- go func() { for { r.Read(buf) } }()
+ go func() {
+ for {
+ r.Read(buf)
+ }
+ }()
for {
w.Write([]byte("ok"))
}
case 2: // unknown user
- go func() { for { r.Read(buf) } }()
+ go func() {
+ for {
+ r.Read(buf)
+ }
+ }()
for {
w.Write([]byte("unknown user"))
}
diff --git a/server.go b/server.go
@@ -64,15 +64,16 @@ type Server struct {
respChan chan *Req
- // Auth function is passed an auth request when a TAuth message arrives.
- // It should run a goroutine listeneing to the channel which the function
- // returns and send processed *Req through the channel specified by the
- // second argument.
+ // Auth function is passed an auth request via authc when a TAuth message
+ // arrives. It is called as a separate goroutine and should listen to
+ // authc and send processed *Req through respc.
+ // Don't close these channels.
// If authentication is desired, the Auth goroutine should
// set Req.Afid.File to an *AuthFile and Req.Ofcall.Qid, and prepare to
- // authenticate via the Read()/Write() calls to Req.Afid.File
+ // authenticate via the Read()/Write() calls to Req.Afid.File.
+ // Auth goroutine should return when ctx is canceled.
// If this is nil, no authentication is performed.
- Auth func(context.Context, chan<- *Req) chan<- *Req
+ Auth func(ctx context.Context, authc <-chan *Req, respc chan<- *Req)
}
// NewServer creates a Server and runs listener and speaker goroutines.
@@ -235,9 +236,10 @@ func sVersion(ctx context.Context, s *Server, c <-chan *Req) {
// sAuth serves Tauth message.
func sAuth(ctx context.Context, s *Server, c <-chan *Req) {
- var authc chan<- *Req
+ var authc chan *Req
if s.Auth != nil {
- authc = s.Auth(ctx, s.respChan)
+ authc = make(chan *Req)
+ go s.Auth(ctx, authc, s.respChan)
defer close(authc)
}
for {
diff --git a/server2_test.go b/server2_test.go
@@ -144,15 +144,15 @@ func TestGetReq(t *testing.T) {
}
func TestSVersion(t *testing.T) {
- tests := []struct{
+ tests := []struct {
input *Req
- want *Req
+ want *Req
}{
{&Req{Ifcall: &TVersion{Msize: 1024, Version: "9P2000"}},
&Req{Ofcall: &RVersion{Msize: 1024, Version: "9P2000"}}},
{&Req{Ifcall: &TVersion{Msize: 564, Version: "9P2000"}},
&Req{Ofcall: &RVersion{Msize: 564, Version: "9P2000"}}},
- {&Req{Ifcall: &TVersion{Msize: 8*1024, Version: "9P2000"}},
+ {&Req{Ifcall: &TVersion{Msize: 8 * 1024, Version: "9P2000"}},
&Req{Ofcall: &RVersion{Msize: 1024, Version: "9P2000"}}},
{&Req{Ifcall: &TVersion{Msize: 1024, Version: "unko"}},
&Req{Ofcall: &RVersion{Msize: 1024, Version: "unknown"}}},
@@ -183,55 +183,47 @@ func TestSVersion(t *testing.T) {
}
func TestSAuth(t *testing.T) {
- tests := []struct{
- input *Req
- want *Req
- authFunc func(context.Context, chan<- *Req) chan<- *Req
+ tests := []struct {
+ input *Req
+ want *Req
+ authFunc func(context.Context, <-chan *Req, chan<- *Req)
}{
{&Req{Ifcall: &TAuth{Afid: NOFID, Uname: "kenji", Aname: ""}},
&Req{Ofcall: &RError{Ename: errors.New("authentication not required")}}, nil},
{&Req{Ifcall: &TAuth{Afid: NOFID, Uname: "kenji", Aname: ""}},
&Req{Ofcall: &RError{Ename: errors.New("NOFID can't be used for afid")}},
- func(ctx context.Context, respc chan<- *Req) chan<- *Req {
- authc := make(chan *Req)
- go func() {
- for {
- select {
- case r, ok := <-authc:
- if !ok {
- return
- }
- respc <- r
- case <-ctx.Done():
+ func(ctx context.Context, authc <-chan *Req, respc chan<- *Req) {
+ for {
+ select {
+ case r, ok := <-authc:
+ if !ok {
return
}
+ respc <- r
+ case <-ctx.Done():
+ return
}
- }()
- return authc
+ }
}},
{&Req{Ifcall: &TAuth{Afid: 0, Uname: "kenji", Aname: ""}},
&Req{Ofcall: &RAuth{Tag: 0, Aqid: Qid{0, 1, 2}}},
- func(ctx context.Context, respc chan<- *Req) chan<- *Req {
- authc := make(chan *Req)
- go func() {
- for {
- select {
- case r, ok := <-authc:
- if !ok {
- return
- }
- r.Ofcall = &RAuth{Tag: 0, Aqid: Qid{0, 1, 2}}
- respc <- r
- case <-ctx.Done():
+ func(ctx context.Context, authc <-chan *Req, respc chan<- *Req) {
+ for {
+ select {
+ case r, ok := <-authc:
+ if !ok {
return
}
+ r.Ofcall = &RAuth{Tag: 0, Aqid: Qid{0, 1, 2}}
+ respc <- r
+ case <-ctx.Done():
+ return
}
- }()
- return authc
+ }
}},
}
for _, test := range tests {
- func () {
+ func() {
tc := make(chan *Req)
rc := make(chan *Req)
defer close(tc)
@@ -264,4 +256,4 @@ func TestSAuth(t *testing.T) {
}
}()
}
-}
-\ No newline at end of file
+}