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: 64 * 1024, version: "9P2000", } go c.muxer() // 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)) } if rx.Version != "9P2000" { return nil, plan9.ProtocolError(fmt.Sprintf("invalid version %s in Rversion", rx.Version)) } c.msize = rx.Msize 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() rx = <-ch if rx == nil { //log.Printf("rpc failed, closed %v, err %v\n", closed(ch), c.getErr()) 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) newtag(ch chan *plan9.Fcall) (uint16, error) { c.x.Lock() defer c.x.Unlock() var tagnum uint16 // for tagnum, _ = range c.freetag { // c.freetag[tagnum] = false, false // goto found // } tagnum = c.nexttag if c.nexttag == plan9.NOTAG { return 0, plan9.ProtocolError("out of tags") } c.nexttag++ //found: c.tagmap[tagnum] = ch return tagnum, nil }
func (c *Conn) getfid() (*Fid, error) { c.x.Lock() defer c.x.Unlock() var fidnum uint32 // for fidnum, _ = range c.freefid { // c.freefid[fidnum] = false, false // goto found // } fidnum = c.nextfid if c.nextfid == plan9.NOFID { return nil, plan9.ProtocolError("out of fids") } c.nextfid++ //found: fid := new(Fid) fid.fid = fidnum fid.c = c return fid, nil }