Blob


1 package p9pnew
3 import (
4 "fmt"
5 "log"
7 "golang.org/x/net/context"
9 "net"
10 )
12 type client struct {
13 version string
14 msize uint32
15 ctx context.Context
16 transport roundTripper
17 }
19 // NewSession returns a session using the connection. The Context ctx provides
20 // a context for out of bad messages, such as flushes, that may be sent by the
21 // session. The session can effectively shutdown with this context.
22 func NewSession(ctx context.Context, conn net.Conn) (Session, error) {
23 const msize = 64 << 10
24 const vers = "9P2000"
26 ch := newChannel(conn, codec9p{}, msize) // sets msize, effectively.
28 // negotiate the protocol version
29 _, err := clientnegotiate(ctx, ch, vers)
30 if err != nil {
31 return nil, err
32 }
34 return &client{
35 version: vers,
36 msize: msize,
37 ctx: ctx,
38 transport: newTransport(ctx, ch),
39 }, nil
40 }
42 var _ Session = &client{}
44 func (c *client) Version() (uint32, string) {
45 return c.msize, c.version
46 }
48 func (c *client) Auth(ctx context.Context, afid Fid, uname, aname string) (Qid, error) {
49 panic("not implemented")
50 }
52 func (c *client) Attach(ctx context.Context, fid, afid Fid, uname, aname string) (Qid, error) {
53 log.Println("client attach", fid, aname)
54 fcall := &Fcall{
55 Type: Tattach,
56 Message: &MessageTattach{
57 Fid: fid,
58 Afid: afid,
59 Uname: uname,
60 Aname: aname,
61 },
62 }
64 resp, err := c.transport.send(ctx, fcall)
65 if err != nil {
66 return Qid{}, err
67 }
69 mrr, ok := resp.Message.(*MessageRattach)
70 if !ok {
71 return Qid{}, fmt.Errorf("invalid rpc response for attach message: %v", resp)
72 }
74 return mrr.Qid, nil
75 }
77 func (c *client) Clunk(ctx context.Context, fid Fid) error {
78 fcall := newFcall(&MessageTclunk{
79 Fid: fid,
80 })
82 resp, err := c.transport.send(ctx, fcall)
83 if err != nil {
84 return err
85 }
87 if resp.Type != Rclunk {
88 return fmt.Errorf("incorrect response type: %v", resp)
89 }
91 return nil
92 }
94 func (c *client) Remove(ctx context.Context, fid Fid) error {
95 panic("not implemented")
96 }
98 func (c *client) Walk(ctx context.Context, fid Fid, newfid Fid, names ...string) ([]Qid, error) {
99 if len(names) > 16 {
100 return nil, fmt.Errorf("too many elements in wname")
103 fcall := &Fcall{
104 Type: Twalk,
105 Message: &MessageTwalk{
106 Fid: fid,
107 Newfid: newfid,
108 Wnames: names,
109 },
112 resp, err := c.transport.send(ctx, fcall)
113 if err != nil {
114 return nil, err
117 mrr, ok := resp.Message.(*MessageRwalk)
118 if !ok {
119 return nil, fmt.Errorf("invalid rpc response for walk message: %v", resp)
122 return mrr.Qids, nil
125 func (c *client) Read(ctx context.Context, fid Fid, p []byte, offset int64) (n int, err error) {
126 // TODO(stevvooe): Split up reads into multiple messages based on iounit.
127 // For now, we just support full blast. I mean, why not?
128 fcall := &Fcall{
129 Type: Tread,
130 Message: &MessageTread{
131 Fid: fid,
132 Offset: uint64(offset),
133 Count: uint32(len(p)),
134 },
137 resp, err := c.transport.send(ctx, fcall)
138 if err != nil {
139 return 0, err
142 mrr, ok := resp.Message.(*MessageRread)
143 if !ok {
144 return 0, fmt.Errorf("invalid rpc response for read message: %v", resp)
147 return copy(p, mrr.Data), nil
150 func (c *client) Write(ctx context.Context, fid Fid, p []byte, offset int64) (n int, err error) {
151 // TODO(stevvooe): Split up writes into multiple messages based on iounit.
152 // For now, we just support full blast. I mean, why not?
153 fcall := &Fcall{
154 Type: Twrite,
155 Message: &MessageTwrite{
156 Fid: fid,
157 Offset: uint64(offset),
158 Data: p,
159 },
162 resp, err := c.transport.send(ctx, fcall)
163 if err != nil {
164 return 0, err
167 mrr, ok := resp.Message.(*MessageRwrite)
168 if !ok {
169 return 0, fmt.Errorf("invalid rpc response for write message: %v", resp)
172 return int(mrr.Count), nil
175 func (c *client) Open(ctx context.Context, fid Fid, mode uint8) (Qid, uint32, error) {
176 fcall := newFcall(&MessageTopen{
177 Fid: fid,
178 Mode: mode,
179 })
181 resp, err := c.transport.send(ctx, fcall)
182 if err != nil {
183 return Qid{}, 0, err
186 respmsg, ok := resp.Message.(*MessageRopen)
187 if !ok {
188 return Qid{}, 0, fmt.Errorf("invalid rpc response for open message: %v", resp)
191 return respmsg.Qid, respmsg.IOUnit, nil
194 func (c *client) Create(ctx context.Context, parent Fid, name string, perm uint32, mode uint32) (Qid, uint32, error) {
195 panic("not implemented")
198 func (c *client) Stat(ctx context.Context, fid Fid) (Dir, error) {
199 fcall := newFcall(MessageTstat{Fid: fid})
201 resp, err := c.transport.send(ctx, fcall)
202 if err != nil {
203 return Dir{}, err
206 respmsg, ok := resp.Message.(*MessageRstat)
207 if !ok {
208 return Dir{}, fmt.Errorf("invalid rpc response for stat message: %v", resp)
211 return respmsg.Stat, nil
214 func (c *client) WStat(context.Context, Fid, Dir) error {
215 panic("not implemented")
218 func (c *client) flush(ctx context.Context, tag Tag) error {
219 // TODO(stevvooe): We need to fire and forget flush messages when a call
220 // context gets cancelled.
222 panic("not implemented")