// Establishes a new socket connection to the 9P server and creates // a client object for it. Negotiates the dialect and msize for the // connection. Returns a Clnt object, or Error. func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) { clnt := NewClnt(c, msize, dotu) ver := "9P2000" if clnt.Dotu { ver = "9P2000.u" } clntmsize := atomic.LoadUint32(&clnt.Msize) tc := p.NewFcall(clntmsize) err := p.PackTversion(tc, clntmsize, ver) if err != nil { return nil, err } rc, err := clnt.Rpc(tc) if err != nil { return nil, err } if rc.Msize < atomic.LoadUint32(&clnt.Msize) { atomic.StoreUint32(&clnt.Msize, rc.Msize) } clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu return clnt, nil }
func (clnt *Clnt) NewFcall() *p.Fcall { select { case tc := <-clnt.tchan: return tc default: } return p.NewFcall(atomic.LoadUint32(&clnt.Msize)) }
func (conn *Conn) recv() { var err error var n int buf := make([]byte, conn.Msize*8) pos := 0 for { if len(buf) < int(conn.Msize) { b := make([]byte, conn.Msize*8) copy(b, buf[0:pos]) buf = b b = nil } n, err = conn.conn.Read(buf[pos:]) if err != nil || n == 0 { conn.close() return } pos += n for pos > 4 { sz, _ := p.Gint32(buf) if sz > conn.Msize { log.Println("bad client connection: ", conn.conn.RemoteAddr()) conn.conn.Close() conn.close() return } if pos < int(sz) { if len(buf) < int(sz) { b := make([]byte, conn.Msize*8) copy(b, buf[0:pos]) buf = b b = nil } break } fc, err, fcsize := p.Unpack(buf, conn.Dotu) if err != nil { log.Println(fmt.Sprintf("invalid packet : %v %v", err, buf)) conn.conn.Close() conn.close() return } tag := fc.Tag req := new(Req) select { case req.Rc = <-conn.rchan: break default: req.Rc = p.NewFcall(conn.Msize) } req.Conn = conn req.Tc = fc // req.Rc = rc if conn.Debuglevel > 0 { conn.logFcall(req.Tc) if conn.Debuglevel&DbgPrintPackets != 0 { log.Println(">->", conn.Id, fmt.Sprint(req.Tc.Pkt)) } if conn.Debuglevel&DbgPrintFcalls != 0 { log.Println(">>>", conn.Id, req.Tc.String()) } } conn.Lock() conn.nreqs++ conn.tsz += uint64(fc.Size) conn.npend++ if conn.npend > conn.maxpend { conn.maxpend = conn.npend } req.next = conn.Reqs[tag] conn.Reqs[tag] = req process := req.next == nil if req.next != nil { req.next.prev = req } conn.Unlock() if process { // Tversion may change some attributes of the // connection, so we block on it. Otherwise, // we may loop back to reading and that is a race. // This fix brought to you by the race detector. if req.Tc.Type == p.Tversion { req.process() } else { go req.process() } } buf = buf[fcsize:] pos -= fcsize } } }