func (y *Conn) Greet() (string, string, os.Error) { y.lk.Lock() if y.err != nil { y.lk.Unlock() return "", "", os.ErrorString("d,conn: closed meantime") } if y.regime != regimeUnAuth || y.tube == nil { panic("d,conn: regime logic") } y.regime = regimeAuth tube := y.tube y.lk.Unlock() g := &U_Greet{sys.Build, Version} err := tube.Encode(g) if err == nil { err = tube.Decode(g) } y.lk.Lock() if y.err != nil { y.lk.Unlock() return "", "", os.ErrorString("d,conn: closed meantime") } if err != nil { y.lk.Unlock() return "", "", y.kill(os.ErrorString("d,conn: greet failed")) } y.regime = regimeUnAuth y.lk.Unlock() return g.Build, g.Version, nil }
func (h *handoff) Read(p []byte) (n int, err os.Error) { tube, err := h.checkForKill() if err != nil { return 0, err } h.lk.Lock() if h.rclosed { h.lk.Unlock() return 0, os.EOF } h.lk.Unlock() // No need to lock on h.buf, since it's only used here, and // concurrent read calls are not allowed. if h.buf.Len() == 0 { msg := &U_Cargo{} if err = tube.Decode(msg); err != nil { return 0, h.kill(err) } // A 0-length cargo is an indication of session EOF if msg.Cargo == nil || len(msg.Cargo) == 0 { h.lk.Lock() defer h.lk.Unlock() if h.y == nil { return 0, os.EBADF } h.rclosed = true return 0, os.EOF } n, _ = h.buf.Write(msg.Cargo) if n != len(msg.Cargo) { panic("d,conn,h: buf write") } h.lk.Lock() h.rn += int64(n) h.rk++ h.lk.Unlock() } if h.buf.Len() == 0 { panic("handoff logic") } n, err = h.buf.Read(p) if err != nil { panic("d,conn,h: buf") } h.lk.Lock() defer h.lk.Unlock() if h.y == nil { return 0, os.EBADF } return n, nil }
// Close terminates this handoff and returns control to the underlying Conn. func (h *handoff) Close() (err os.Error) { h.lk.Lock() y := h.y h.y = nil if y == nil { h.lk.Unlock() return os.EBADF } rclosed := h.rclosed h.lk.Unlock() //fmt.Printf(term.FgCyan+"d·conn[%#p]·h[%#p]:%x —— close\n"+term.Reset, y,h,h.session) tube, err := y.getTube() if err != nil { return os.EIO } msg := &U_Cargo{} if err = tube.Encode(msg); err != nil { return h.kill(err) } if !rclosed { msg := &U_Cargo{} if err = tube.Decode(msg); err != nil { goto __End } if msg.Cargo == nil || len(msg.Cargo) == 0 { goto __End } } __End: h.lk.Lock() ff := h.finfun h.finfun = nil h.lk.Unlock() if ff != nil { ff() } if err != nil { err = y.kill(err) } return err }
func (y *Conn) Poll() (subject string, rwc io.ReadWriteCloser, err os.Error) { for { y.hlk.Lock() y.hlk.Unlock() //fmt.Printf(term.FgBlack + "d·conn[%#p] —— loop\n" + term.Reset, y) y.lk.Lock() if y.err != nil || y.tube == nil { y.lk.Unlock() return "", nil, os.EBADF } tube := y.tube y.lk.Unlock() tch := waitForRead(tube.ExposeBufioReader()) select { case m := <-y.dialch: // dial & kill requests come here if m == nil { //fmt.Printf(term.FgRed + "d·conn[%#p] —— closing accept loop\n"+ term.Reset, y) err = os.EBADF return "", nil, err } //fmt.Printf(term.FgYellow + "d·conn[%#p] —— dialing, subject=%s\n" + term.Reset, y, m.Subject) order := y.getRandOrient() session := y.getRandSession() orient := &U_Orient{order, session} if err = tube.Encode(orient); err != nil { err = y.kill(err) m.Notify <- nil return "", nil, err } err = <-tch // Hack. Reuse wait until data from remote if err != nil { //fmt.Printf(term.FgRed+"d·conn[%#p] —— dial/orient err: %s\n"+ term.Reset, y, err) err = y.kill(err) m.Notify <- nil return "", nil, err } err = tube.Decode(orient) if err != nil { //fmt.Printf(term.FgCyan+"d·conn[%#p] —— orient,dec: %s\n"+ term.Reset, y, err) err = y.kill(err) m.Notify <- nil return "", nil, err } if orient.Order >= order { // our dial prevails y.sendCall(session, m, tube) } else { // remote dial prevails m.Notify <- nil return y.receiveCall(orient.Session, tube) } case err = <-tch: // read is available on the connection if err != nil { //fmt.Printf(term.FgRed+"d·conn[%#p] —— ring/orient err: %s\n"+ term.Reset, y, err) err = y.kill(err) return "", nil, err } orient := &U_Orient{} if err = tube.Decode(orient); err != nil { //fmt.Printf(term.FgRed+"d·conn[%#p] —— ori,dec,err: %s\n"+ term.Reset, y, err) err = y.kill(err) return "", nil, err } orient.Order++ session := orient.Session if err = tube.Encode(orient); err != nil { //fmt.Printf(term.FgRed+"d·conn[%#p] —— ori,enc,err: %s\n"+ term.Reset, y, err) err = y.kill(err) return "", nil, err } return y.receiveCall(session, tube) } // select } // for panic("unreach") }