func NewConn(rwc io.ReadWriteCloser) (*Conn, error) { c := &Conn{ rwc: rwc, tagmap: make(map[uint16]chan *plan9.Fcall), freetag: make(map[uint16]bool), freefid: make(map[uint32]bool), nexttag: 1, nextfid: 1, msize: 131072, version: "9P2000", } // XXX raw messages, not c.rpc tx := &plan9.Fcall{Type: plan9.Tversion, Msize: c.msize, Version: c.version} rx, err := c.rpc(tx) if err != nil { return nil, err } if rx.Msize > c.msize { return nil, plan9.ProtocolError(fmt.Sprintf("invalid msize %d in Rversion", rx.Msize)) } c.msize = rx.Msize if rx.Version != "9P2000" { return nil, plan9.ProtocolError(fmt.Sprintf("invalid version %s in Rversion", rx.Version)) } return c, nil }
func (c *Conn) rpc(tx *plan9.Fcall) (rx *plan9.Fcall, err error) { ch := make(chan *plan9.Fcall, 1) tx.Tag, err = c.newtag(ch) if err != nil { return nil, err } c.w.Lock() if err := c.write(tx); err != nil { c.w.Unlock() return nil, err } c.w.Unlock() for rx = range ch { if rx != &yourTurn { break } rx, err = c.read() if err != nil { break } c.mux(rx) } if rx == nil { return nil, c.getErr() } if rx.Type == plan9.Rerror { return nil, Error(rx.Ename) } if rx.Type != tx.Type+1 { return nil, plan9.ProtocolError("packet type mismatch") } return rx, nil }
func (c *Conn) newfid() (*Fid, error) { c.x.Lock() defer c.x.Unlock() var fidnum uint32 for fidnum, _ = range c.freefid { delete(c.freefid, fidnum) goto found } fidnum = c.nextfid if c.nextfid == plan9.NOFID { return nil, plan9.ProtocolError("out of fids") } c.nextfid++ found: return &Fid{fid: fidnum, c: c}, nil }
func (c *Conn) newtag(ch chan *plan9.Fcall) (uint16, error) { c.x.Lock() defer c.x.Unlock() var tagnum uint16 for tagnum, _ = range c.freetag { delete(c.freetag, tagnum) goto found } tagnum = c.nexttag if c.nexttag == plan9.NOTAG { return 0, plan9.ProtocolError("out of tags") } c.nexttag++ found: c.tagmap[tagnum] = ch if !c.muxer { c.muxer = true ch <- &yourTurn } return tagnum, nil }