commit e3315609106a109686816ddb5772eb7de2807a77
parent 72c9a8f3eefc0ab1eb1509e6acd24a948345cc90
Author: Matsuda Kenji <info@mtkn.jp>
Date: Sun, 31 Dec 2023 09:18:55 +0900
add conn struct
Diffstat:
M | server.go | | | 337 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
1 file changed, 171 insertions(+), 166 deletions(-)
diff --git a/server.go b/server.go
@@ -37,17 +37,37 @@ type Server struct {
// The file system to export via 9P.
fs FS
+ // Auth function is passed an auth request when a TAuth message arrives
+ // If authentication is desired, Auth should
+ // set request.Afid.file to an *AuthFile and request.ofcall.Qid, and prepare to
+ // authenticate via the Read()/Write() calls to request.Afid.file.
+ // Auth should clean up everything it creates when ctx is canceled.
+ // If this is nil, no authentication is performed.
+ Auth func(ctx context.Context, r *request)
+}
+
+// NewServer creates a Server and runs listener and responder goroutines.
+// It reads incoming messages from r and writes responses to w.
+func NewServer(fsys FS) *Server {
+ s := &Server{
+ fs: fsys,
+ }
+ return s
+}
+
+// Chatty enables the server's log messages of 9P messages.
+func (s *Server) Chatty() { s.chatty9P = true }
+
+type conn struct {
+ s *Server
// Maximum length in byte of 9P messages.
msize uint32
// Mutex to change msize.
mSizeLock *sync.Mutex
- // FidPool of the Server.
+ // FidPool of the connection.
fPool *fidPool
- // Pending Requests the server is dealing with.
- rPool *reqPool
-
// The channel from which incoming requests are delivered by the
// listener goroutine.
listenChan <-chan *request
@@ -62,59 +82,43 @@ type Server struct {
// w is the io.Writer which the responder goroutine writes to.
// It should be accessed only by the responder goroutine.
w io.Writer
-
- // Auth function is passed an auth request when a TAuth message arrives
- // If authentication is desired, Auth should
- // set request.Afid.file to an *AuthFile and request.ofcall.Qid, and prepare to
- // authenticate via the Read()/Write() calls to request.Afid.file.
- // Auth should clean up everything it creates when ctx is canceled.
- // If this is nil, no authentication is performed.
- Auth func(ctx context.Context, r *request)
}
-// NewServer creates a Server and runs listener and responder goroutines.
-// It reads incoming messages from r and writes responses to w.
-func NewServer(fsys FS, mSize uint32, r io.Reader, w io.Writer) *Server {
- s := &Server{
- fs: fsys,
- msize: mSize,
+func newConn(r io.Reader, w io.Writer) *conn {
+ return &conn{
+ msize: 8*1024,
mSizeLock: new(sync.Mutex),
- fPool: newFidPool(),
- r: r,
- w: w,
- respChan: make(chan *request),
+ fPool: newFidPool(),
+ r: r,
+ w: w,
}
- return s
}
-// Chatty enables the server's log messages of 9P messages.
-func (s *Server) Chatty() { s.chatty9P = true }
-
// mSize reads the maximum message size of the server.
-func (s *Server) mSize() uint32 {
- s.mSizeLock.Lock()
- defer s.mSizeLock.Unlock()
- return s.msize
+func (c *conn) mSize() uint32 {
+ c.mSizeLock.Lock()
+ defer c.mSizeLock.Unlock()
+ return c.msize
}
// setMSize changes the server's maximum message size.
-func (s *Server) setMSize(mSize uint32) {
- s.mSizeLock.Lock()
- defer s.mSizeLock.Unlock()
- s.msize = mSize
+func (c *conn) setMSize(mSize uint32) {
+ c.mSizeLock.Lock()
+ defer c.mSizeLock.Unlock()
+ c.msize = mSize
}
// runListener runs the listener goroutine.
// Listener goroutine reads 9P messages from s.r by calling getReq
// and allocats request for each of them, and sends it to the server's listenChan.
-func (s *Server) runListener(ctx context.Context, rp *reqPool) {
+func (c *conn) runListener(ctx context.Context, rp *reqPool) {
rc := make(chan *request)
- s.listenChan = rc
+ c.listenChan = rc
go func() {
defer close(rc)
for {
select {
- case rc <- getReq(s.r, rp, s.chatty9P):
+ case rc <- getReq(c.r, rp, c.s.chatty9P):
case <-ctx.Done():
return
}
@@ -124,10 +128,10 @@ func (s *Server) runListener(ctx context.Context, rp *reqPool) {
// runResponder runs the responder goroutine.
// Responder goroutine wait for reply Requests from the returned channel,
-// and marshalls each of them into 9P messages and writes it to s.w.
-func (s *Server) runResponder(ctx context.Context, rp *reqPool) {
+// and marshalls each of them into 9P messages and writes it to c.w.
+func (c *conn) runResponder(ctx context.Context, rp *reqPool) {
rc := make(chan *request)
- s.respChan = rc
+ c.respChan = rc
go func() {
for {
select {
@@ -138,13 +142,13 @@ func (s *Server) runResponder(ctx context.Context, rp *reqPool) {
r.ofcall.SetTag(r.tag)
// free tag.
rp.delete(r.tag)
- _, err := s.w.Write(r.ofcall.marshal())
+ _, err := c.w.Write(r.ofcall.marshal())
if err != nil {
// TODO: handle error.
log.Printf("respond: %v", err)
continue
}
- if s.chatty9P {
+ if c.s.chatty9P {
fmt.Fprintf(os.Stderr, "--> %s\n", r.ofcall)
}
case <-ctx.Done():
@@ -154,7 +158,7 @@ func (s *Server) runResponder(ctx context.Context, rp *reqPool) {
}()
}
-// GetReq reads 9P message from s.r, allocates request, adds it to s.rPool,
+// GetReq reads 9P message from r, allocates request, adds it to s.rPool,
// and returns it.
// Any error it encountered is embedded into the request struct.
// This function is called only by the server's listener goroutine,
@@ -199,12 +203,12 @@ func getReq(r io.Reader, rp *reqPool, chatty bool) *request {
// server's mSize to the message's one.
// TODO: abort all outstanding I/O on the same connection before
// serving new Tversion.
-func sVersion(ctx context.Context, s *Server, c <-chan *request) {
+func sVersion(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
@@ -216,16 +220,16 @@ func sVersion(ctx context.Context, s *Server, c <-chan *request) {
version = "9P2000"
}
msize := ifcall.Msize
- if msize > s.mSize() {
- msize = s.mSize()
+ if msize > c.mSize() {
+ msize = c.mSize()
}
r.ofcall = &RVersion{
Msize: msize,
Version: version,
}
- s.setMSize(r.ofcall.(*RVersion).Msize)
+ c.setMSize(r.ofcall.(*RVersion).Msize)
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -234,19 +238,19 @@ func sVersion(ctx context.Context, s *Server, c <-chan *request) {
}
// sAuth serves Tauth message.
-func sAuth(ctx context.Context, s *Server, c <-chan *request) {
+func sAuth(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
- if s.Auth == nil {
+ if c.s.Auth == nil {
setError(r, fmt.Errorf("authentication not required"))
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -257,34 +261,34 @@ func sAuth(ctx context.Context, s *Server, c <-chan *request) {
if ifcall.Afid == NOFID {
setError(r, fmt.Errorf("NOFID can't be used for afid")) // TODO: really?
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
continue
}
- r.afid, err = s.fPool.add(ifcall.Afid)
+ r.afid, err = c.fPool.add(ifcall.Afid)
if err != nil {
setError(r, ErrDupFid)
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
continue
}
- s.Auth(ctx, r)
- s.respChan <- r
+ c.s.Auth(ctx, r)
+ c.respChan <- r
}
}
}
-func sAttach(ctx context.Context, s *Server, c <-chan *request) {
+func sAttach(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
var (
st fs.FileInfo
err error
@@ -293,21 +297,21 @@ func sAttach(ctx context.Context, s *Server, c <-chan *request) {
return
}
ifcall := r.ifcall.(*TAttach)
- r.fid, err = s.fPool.add(ifcall.Fid)
+ r.fid, err = c.fPool.add(ifcall.Fid)
if err != nil {
r.err = ErrDupFid
goto resp
}
switch {
- case s.Auth == nil && ifcall.Afid == NOFID:
- case s.Auth == nil && ifcall.Afid != NOFID:
+ case c.s.Auth == nil && ifcall.Afid == NOFID:
+ case c.s.Auth == nil && ifcall.Afid != NOFID:
r.err = ErrBotch
goto resp
- case s.Auth != nil && ifcall.Afid == NOFID:
+ case c.s.Auth != nil && ifcall.Afid == NOFID:
r.err = fmt.Errorf("authentication required")
goto resp
- case s.Auth != nil && ifcall.Afid != NOFID:
- afid, ok := s.fPool.lookup(ifcall.Afid)
+ case c.s.Auth != nil && ifcall.Afid != NOFID:
+ afid, ok := c.fPool.lookup(ifcall.Afid)
if !ok {
r.err = ErrUnknownFid
goto resp
@@ -325,7 +329,7 @@ func sAttach(ctx context.Context, s *Server, c <-chan *request) {
r.fid.omode = -1
r.fid.path = "."
r.fid.uid = ifcall.Uname
- st, err = fs.Stat(ExportFS{s.fs}, ".")
+ st, err = fs.Stat(ExportFS{c.s.fs}, ".")
if err != nil {
r.err = fmt.Errorf("stat root: %v", err)
goto resp
@@ -336,12 +340,12 @@ func sAttach(ctx context.Context, s *Server, c <-chan *request) {
resp:
if r.err != nil {
if r.fid != nil {
- s.fPool.delete(r.fid.fid)
+ c.fPool.delete(r.fid.fid)
}
setError(r, r.err)
}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -349,12 +353,12 @@ func sAttach(ctx context.Context, s *Server, c <-chan *request) {
}
}
-func sFlush(ctx context.Context, s *Server, c <-chan *request) {
+func sFlush(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
@@ -363,7 +367,7 @@ func sFlush(ctx context.Context, s *Server, c <-chan *request) {
}
r.ofcall = &RFlush{}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -371,12 +375,12 @@ func sFlush(ctx context.Context, s *Server, c <-chan *request) {
}
}
-func sWalk(ctx context.Context, s *Server, c <-chan *request) {
+func sWalk(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
@@ -389,7 +393,7 @@ func sWalk(ctx context.Context, s *Server, c <-chan *request) {
n int
)
ifcall := r.ifcall.(*TWalk)
- oldFid, ok := s.fPool.lookup(ifcall.Fid)
+ oldFid, ok := c.fPool.lookup(ifcall.Fid)
if !ok {
r.err = ErrUnknownFid
goto resp
@@ -398,7 +402,7 @@ func sWalk(ctx context.Context, s *Server, c <-chan *request) {
r.err = fmt.Errorf("cannot clone open fid")
goto resp
}
- oldst, err = fs.Stat(ExportFS{s.fs}, oldFid.path)
+ oldst, err = fs.Stat(ExportFS{c.s.fs}, oldFid.path)
if err != nil {
r.err = fmt.Errorf("stat: %v", err)
goto resp
@@ -411,7 +415,7 @@ func sWalk(ctx context.Context, s *Server, c <-chan *request) {
newFid = oldFid
} else {
var err error
- newFid, err = s.fPool.add(ifcall.Newfid)
+ newFid, err = c.fPool.add(ifcall.Newfid)
if err != nil {
r.err = fmt.Errorf("alloc: %v", err)
goto resp
@@ -422,7 +426,7 @@ func sWalk(ctx context.Context, s *Server, c <-chan *request) {
// TODO: replace this block with fs.WalkDir.
for i, name := range ifcall.Wnames {
cwdp = path.Join(cwdp, name)
- stat, err := fs.Stat(ExportFS{s.fs}, cwdp)
+ stat, err := fs.Stat(ExportFS{c.s.fs}, cwdp)
if err != nil {
break
}
@@ -441,13 +445,13 @@ func sWalk(ctx context.Context, s *Server, c <-chan *request) {
panic("err and r.ofcall are both nil")
}
setError(r, r.err)
- s.respChan <- r
+ c.respChan <- r
continue
}
ofcall := r.ofcall.(*RWalk)
if r.err != nil || len(ofcall.Qids) < len(ifcall.Wnames) {
if ifcall.Fid != ifcall.Newfid {
- s.fPool.delete(ifcall.Newfid)
+ c.fPool.delete(ifcall.Newfid)
}
if len(ofcall.Qids) == 0 {
if r.err == nil && len(ifcall.Wnames) != 0 {
@@ -456,7 +460,7 @@ func sWalk(ctx context.Context, s *Server, c <-chan *request) {
}
}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -464,12 +468,12 @@ func sWalk(ctx context.Context, s *Server, c <-chan *request) {
}
}
-func sOpen(ctx context.Context, s *Server, c <-chan *request) {
+func sOpen(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
@@ -480,7 +484,7 @@ func sOpen(ctx context.Context, s *Server, c <-chan *request) {
st fs.FileInfo
)
ifcall := r.ifcall.(*TOpen)
- r.fid, ok = s.fPool.lookup(ifcall.Fid)
+ r.fid, ok = c.fPool.lookup(ifcall.Fid)
if !ok {
r.err = ErrUnknownFid
goto resp
@@ -490,7 +494,7 @@ func sOpen(ctx context.Context, s *Server, c <-chan *request) {
goto resp
}
if afile, ok := r.fid.file.(*AuthFile); ok {
- // s.Auth should set r.fid.file to a valid *AuthFile,
+ // c.s.Auth should set r.fid.file to a valid *AuthFile,
// so r.fid.file should not be nil.
st, err = r.fid.file.Stat()
if err != nil {
@@ -503,7 +507,7 @@ func sOpen(ctx context.Context, s *Server, c <-chan *request) {
// See open(5).
// In plan9 implementation, ifcall.Mode() is ANDed with ^ORCLOSE,
// but ORCLOSE is also prohibitted by the protocol...
- st, err = fs.Stat(ExportFS{s.fs}, r.fid.path)
+ st, err = fs.Stat(ExportFS{c.s.fs}, r.fid.path)
if err != nil {
r.err = fmt.Errorf("stat: %v", err)
goto resp
@@ -533,31 +537,31 @@ func sOpen(ctx context.Context, s *Server, c <-chan *request) {
r.err = ErrPerm
goto resp
}
- if !hasPerm(s.fs, st, r.fid.uid, p) {
+ if !hasPerm(c.s.fs, st, r.fid.uid, p) {
r.err = ErrPerm
goto resp
}
if ifcall.Mode&ORCLOSE != 0 {
parentPath := path.Dir(r.fid.path)
- st, err := fs.Stat(ExportFS{s.fs}, parentPath)
+ st, err := fs.Stat(ExportFS{c.s.fs}, parentPath)
if err != nil {
r.err = fmt.Errorf("stat parent: %v", err)
goto resp
}
- if !hasPerm(s.fs, st, r.fid.uid, AWRITE) {
+ if !hasPerm(c.s.fs, st, r.fid.uid, AWRITE) {
r.err = ErrPerm
goto resp
}
}
r.ofcall = &ROpen{
Qid: qid,
- Iounit: s.mSize() - IOHDRSZ,
+ Iounit: c.mSize() - IOHDRSZ,
}
resp:
if r.err != nil {
setError(r, r.err)
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -566,17 +570,17 @@ func sOpen(ctx context.Context, s *Server, c <-chan *request) {
r.fid.omode = r.ifcall.(*TOpen).Mode
if _, ok := r.fid.file.(*AuthFile); ok {
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
continue
}
- f, err := s.fs.OpenFile(r.fid.path, r.fid.omode)
+ f, err := c.s.fs.OpenFile(r.fid.path, r.fid.omode)
if err != nil {
setError(r, err)
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -584,7 +588,7 @@ func sOpen(ctx context.Context, s *Server, c <-chan *request) {
}
r.fid.file = f
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -592,12 +596,12 @@ func sOpen(ctx context.Context, s *Server, c <-chan *request) {
}
}
-func sCreate(ctx context.Context, s *Server, c <-chan *request) {
+func sCreate(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
@@ -612,12 +616,12 @@ func sCreate(ctx context.Context, s *Server, c <-chan *request) {
dirperm FileMode
)
ifcall := r.ifcall.(*TCreate)
- r.fid, ok = s.fPool.lookup(ifcall.Fid)
+ r.fid, ok = c.fPool.lookup(ifcall.Fid)
if !ok {
r.err = ErrUnknownFid
goto resp
}
- dirstat, err = fs.Stat(ExportFS{s.fs}, r.fid.path)
+ dirstat, err = fs.Stat(ExportFS{c.s.fs}, r.fid.path)
if err != nil {
r.err = fmt.Errorf("stat: %v", err)
goto resp
@@ -626,11 +630,11 @@ func sCreate(ctx context.Context, s *Server, c <-chan *request) {
r.err = fmt.Errorf("create in non-dir")
goto resp
}
- if !hasPerm(s.fs, dirstat, r.fid.uid, AWRITE) {
+ if !hasPerm(c.s.fs, dirstat, r.fid.uid, AWRITE) {
r.err = ErrPerm
goto resp
}
- cfs, ok = s.fs.(CreaterFS)
+ cfs, ok = c.s.fs.(CreaterFS)
if !ok {
r.err = ErrOperation
goto resp
@@ -658,14 +662,14 @@ func sCreate(ctx context.Context, s *Server, c <-chan *request) {
}
r.ofcall = &RCreate{
Qid: st.Sys().(*Stat).Qid,
- Iounit: s.mSize() - IOHDRSZ,
+ Iounit: c.mSize() - IOHDRSZ,
}
resp:
if r.err != nil {
setError(r, r.err)
}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -675,12 +679,12 @@ func sCreate(ctx context.Context, s *Server, c <-chan *request) {
// TODO: I think the file should be locked while reading.
// or should the undeterminism left for the client side?
-func sRead(ctx context.Context, s *Server, c <-chan *request) {
+func sRead(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
var (
fi fs.FileInfo
err error
@@ -692,7 +696,7 @@ func sRead(ctx context.Context, s *Server, c <-chan *request) {
return
}
ifcall := r.ifcall.(*TRead)
- r.fid, ok = s.fPool.lookup(ifcall.Fid)
+ r.fid, ok = c.fPool.lookup(ifcall.Fid)
if !ok {
r.err = ErrUnknownFid
goto resp
@@ -719,7 +723,7 @@ func sRead(ctx context.Context, s *Server, c <-chan *request) {
errc <- fmt.Errorf("invalid dir offset")
return
}
- children, err := fs.Glob(ExportFS{s.fs}, path.Join(r.fid.path, "*"))
+ children, err := fs.Glob(ExportFS{c.s.fs}, path.Join(r.fid.path, "*"))
if err != nil {
errc <- fmt.Errorf("glob children: %v", err)
return
@@ -730,7 +734,7 @@ func sRead(ctx context.Context, s *Server, c <-chan *request) {
}
k := r.fid.dirIndex
for ; k < len(children); k++ {
- fi, err := fs.Stat(ExportFS{s.fs}, children[k])
+ fi, err := fs.Stat(ExportFS{c.s.fs}, children[k])
if err != nil {
log.Printf("stat: %v", err)
continue
@@ -780,7 +784,7 @@ func sRead(ctx context.Context, s *Server, c <-chan *request) {
setError(r, r.err)
}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -789,12 +793,12 @@ func sRead(ctx context.Context, s *Server, c <-chan *request) {
}
// TODO: I think the file should be locked while writing.
-func sWrite(ctx context.Context, s *Server, c <-chan *request) {
+func sWrite(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
@@ -804,13 +808,13 @@ func sWrite(ctx context.Context, s *Server, c <-chan *request) {
omode OpenMode
)
ifcall := r.ifcall.(*TWrite)
- r.fid, ok = s.fPool.lookup(ifcall.Fid)
+ r.fid, ok = c.fPool.lookup(ifcall.Fid)
if !ok {
r.err = ErrUnknownFid
goto resp
}
- if ifcall.Count > s.mSize()-IOHDRSZ {
- ifcall.Count = s.mSize() - IOHDRSZ
+ if ifcall.Count > c.mSize()-IOHDRSZ {
+ ifcall.Count = c.mSize() - IOHDRSZ
}
omode = r.fid.omode & 3
if omode != OWRITE && omode != ORDWR {
@@ -858,7 +862,7 @@ func sWrite(ctx context.Context, s *Server, c <-chan *request) {
setError(r, r.err)
}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -866,22 +870,22 @@ func sWrite(ctx context.Context, s *Server, c <-chan *request) {
}
}
-func sClunk(ctx context.Context, s *Server, c <-chan *request) {
+func sClunk(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
ifcall := r.ifcall.(*TClunk)
- fid, ok := s.fPool.lookup(ifcall.Fid)
+ fid, ok := c.fPool.lookup(ifcall.Fid)
if !ok {
r.err = ErrUnknownFid
goto resp
}
- s.fPool.delete(ifcall.Fid)
+ c.fPool.delete(ifcall.Fid)
if fid.omode != -1 {
if err := fid.file.Close(); err != nil {
r.err = fmt.Errorf("close: %v", err)
@@ -895,7 +899,7 @@ func sClunk(ctx context.Context, s *Server, c <-chan *request) {
r.ofcall = &RClunk{}
}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -903,12 +907,12 @@ func sClunk(ctx context.Context, s *Server, c <-chan *request) {
}
}
-func sRemove(ctx context.Context, s *Server, c <-chan *request) {
+func sRemove(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
@@ -919,26 +923,26 @@ func sRemove(ctx context.Context, s *Server, c <-chan *request) {
rfs RemoverFS
)
ifcall := r.ifcall.(*TRemove)
- r.fid, ok = s.fPool.lookup(ifcall.Fid)
+ r.fid, ok = c.fPool.lookup(ifcall.Fid)
if !ok {
r.err = ErrUnknownFid
goto resp
}
- s.fPool.delete(ifcall.Fid)
+ c.fPool.delete(ifcall.Fid)
if r.fid.omode != -1 {
r.fid.file.Close()
}
parentPath = path.Dir(r.fid.path)
- pstat, err = fs.Stat(ExportFS{s.fs}, parentPath)
+ pstat, err = fs.Stat(ExportFS{c.s.fs}, parentPath)
if err != nil {
r.err = fmt.Errorf("stat parent: %v", err)
goto resp
}
- if !hasPerm(s.fs, pstat, r.fid.uid, AWRITE) {
+ if !hasPerm(c.s.fs, pstat, r.fid.uid, AWRITE) {
r.err = ErrPerm
goto resp
}
- rfs, ok = s.fs.(RemoverFS)
+ rfs, ok = c.s.fs.(RemoverFS)
if !ok {
r.err = ErrOperation
goto resp
@@ -953,7 +957,7 @@ func sRemove(ctx context.Context, s *Server, c <-chan *request) {
setError(r, r.err)
}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -961,12 +965,12 @@ func sRemove(ctx context.Context, s *Server, c <-chan *request) {
}
}
-func sStat(ctx context.Context, s *Server, c <-chan *request) {
+func sStat(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
@@ -975,12 +979,12 @@ func sStat(ctx context.Context, s *Server, c <-chan *request) {
err error
)
ifcall := r.ifcall.(*TStat)
- r.fid, ok = s.fPool.lookup(ifcall.Fid)
+ r.fid, ok = c.fPool.lookup(ifcall.Fid)
if !ok {
r.err = ErrUnknownFid
goto resp
}
- fi, err = fs.Stat(ExportFS{s.fs}, r.fid.path)
+ fi, err = fs.Stat(ExportFS{c.s.fs}, r.fid.path)
if err != nil {
r.err = fmt.Errorf("stat: %v", err)
goto resp
@@ -993,7 +997,7 @@ func sStat(ctx context.Context, s *Server, c <-chan *request) {
setError(r, r.err)
}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -1001,12 +1005,12 @@ func sStat(ctx context.Context, s *Server, c <-chan *request) {
}
}
-func sWStat(ctx context.Context, s *Server, c <-chan *request) {
+func sWStat(ctx context.Context, c *conn, rc <-chan *request) {
for {
select {
case <-ctx.Done():
return
- case r, ok := <-c:
+ case r, ok := <-rc:
if !ok {
return
}
@@ -1018,14 +1022,14 @@ func sWStat(ctx context.Context, s *Server, c <-chan *request) {
err error
)
ifcall := r.ifcall.(*TWStat)
- r.fid, ok = s.fPool.lookup(ifcall.Fid)
+ r.fid, ok = c.fPool.lookup(ifcall.Fid)
if !ok {
r.err = ErrUnknownFid
goto resp
}
if r.fid.omode == -1 {
var err error
- r.fid.file, err = s.fs.OpenFile(r.fid.path, OREAD)
+ r.fid.file, err = c.s.fs.OpenFile(r.fid.path, OREAD)
if err != nil {
r.err = fmt.Errorf("open: %v", err)
goto resp
@@ -1057,12 +1061,12 @@ func sWStat(ctx context.Context, s *Server, c <-chan *request) {
}
if wstat.Name != "" && newStat.Name != wstat.Name {
parentPath := path.Dir(r.fid.path)
- pstat, err := fs.Stat(ExportFS{s.fs}, parentPath)
+ pstat, err := fs.Stat(ExportFS{c.s.fs}, parentPath)
if err != nil {
r.err = fmt.Errorf("stat parent: %v", err)
goto resp
}
- if !hasPerm(s.fs, pstat, r.fid.uid, AWRITE) {
+ if !hasPerm(c.s.fs, pstat, r.fid.uid, AWRITE) {
r.err = ErrPerm
goto resp
}
@@ -1072,7 +1076,7 @@ func sWStat(ctx context.Context, s *Server, c <-chan *request) {
// an existing file.
// but 9pfs, 9pfuse does the rename when used with `git init`.
/*
- children, err := fs.Glob(ExportFS{s.fs}, path.Join(parentPath, "*"))
+ children, err := fs.Glob(ExportFS{c.s.fs}, path.Join(parentPath, "*"))
if err != nil {
r.err = fmt.Errorf("glob children: %v", err)
goto resp
@@ -1087,14 +1091,14 @@ func sWStat(ctx context.Context, s *Server, c <-chan *request) {
newStat.Name = wstat.Name
}
if wstat.Length != ^int64(0) && wstat.Length != newStat.Length {
- if fi.IsDir() || !hasPerm(s.fs, fi, r.fid.uid, AWRITE) {
+ if fi.IsDir() || !hasPerm(c.s.fs, fi, r.fid.uid, AWRITE) {
r.err = ErrPerm
goto resp
}
newStat.Length = wstat.Length
}
if wstat.Mode != FileMode(^uint32(0)) && wstat.Mode != newStat.Mode {
- // the owner of the file or the group leader of the file's group.
+ // the owner of the file or the group leader of the file'c group.
if r.fid.uid != newStat.Uid && r.fid.uid != newStat.Gid {
r.err = ErrPerm
goto resp
@@ -1106,7 +1110,7 @@ func sWStat(ctx context.Context, s *Server, c <-chan *request) {
newStat.Mode = wstat.Mode
}
if wstat.Mtime != ^uint32(0) && wstat.Mtime != newStat.Mtime {
- // the owner of the file or the group leader of the file's group.
+ // the owner of the file or the group leader of the file'c group.
if r.fid.uid != newStat.Uid && r.fid.uid != newStat.Gid {
r.err = ErrPerm
goto resp
@@ -1115,11 +1119,11 @@ func sWStat(ctx context.Context, s *Server, c <-chan *request) {
}
if wstat.Gid != "" && wstat.Gid != newStat.Gid {
// by the owner if also a member of the new group;
- // or by the group leader of the file's current group if
+ // or by the group leader of the file'c current group if
// also the leader of the new group.
- if r.fid.uid == newStat.Uid && s.fs.IsGroupMember(wstat.Gid, r.fid.uid) ||
- s.fs.IsGroupLeader(newStat.Gid, r.fid.uid) &&
- s.fs.IsGroupLeader(wstat.Gid, r.fid.uid) {
+ if r.fid.uid == newStat.Uid && c.s.fs.IsGroupMember(wstat.Gid, r.fid.uid) ||
+ c.s.fs.IsGroupLeader(newStat.Gid, r.fid.uid) &&
+ c.s.fs.IsGroupLeader(wstat.Gid, r.fid.uid) {
newStat.Gid = wstat.Gid
} else {
r.err = ErrPerm
@@ -1137,7 +1141,7 @@ func sWStat(ctx context.Context, s *Server, c <-chan *request) {
setError(r, r.err)
}
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}
@@ -1151,10 +1155,11 @@ func sWStat(ctx context.Context, s *Server, c <-chan *request) {
// the same file concurrentry.
// So some additional struct to represent each connection is needed.
// And Serve method should be attached to that struct.
-func (s *Server) Serve(ctx context.Context) {
+func (s *Server) Serve(ctx context.Context, r io.Reader, w io.Writer) {
rp := newReqPool()
- s.runListener(ctx, rp)
- s.runResponder(ctx, rp)
+ c := newConn(r, w)
+ c.runListener(ctx, rp)
+ c.runResponder(ctx, rp)
var (
versionChan = make(chan *request)
authChan = make(chan *request)
@@ -1185,25 +1190,25 @@ func (s *Server) Serve(ctx context.Context) {
close(statChan)
close(wstatChan)
}()
- go sVersion(ctx, s, versionChan)
- go sAuth(ctx, s, authChan)
- go sAttach(ctx, s, attachChan)
- go sFlush(ctx, s, flushChan)
- go sWalk(ctx, s, walkChan)
- go sOpen(ctx, s, openChan)
- go sCreate(ctx, s, createChan)
- go sRead(ctx, s, readChan)
- go sWrite(ctx, s, writeChan)
- go sClunk(ctx, s, clunkChan)
- go sRemove(ctx, s, removeChan)
- go sStat(ctx, s, statChan)
- go sWStat(ctx, s, wstatChan)
+ go sVersion(ctx, c, versionChan)
+ go sAuth(ctx, c, authChan)
+ go sAttach(ctx, c, attachChan)
+ go sFlush(ctx, c, flushChan)
+ go sWalk(ctx, c, walkChan)
+ go sOpen(ctx, c, openChan)
+ go sCreate(ctx, c, createChan)
+ go sRead(ctx, c, readChan)
+ go sWrite(ctx, c, writeChan)
+ go sClunk(ctx, c, clunkChan)
+ go sRemove(ctx, c, removeChan)
+ go sStat(ctx, c, statChan)
+ go sWStat(ctx, c, wstatChan)
L:
for {
select {
case <-ctx.Done():
break L
- case r, ok := <-s.listenChan:
+ case r, ok := <-c.listenChan:
if !ok {
break L
}
@@ -1218,7 +1223,7 @@ L:
default:
setError(r, fmt.Errorf("unknown message type: %d", r.ifcall.Type()))
select {
- case s.respChan <- r:
+ case c.respChan <- r:
case <-ctx.Done():
return
}