forked from docker-archive/go-p9p
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathssesssion.go
152 lines (135 loc) · 3.69 KB
/
ssesssion.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package p9p
import "context"
// Handler defines an interface for 9p message handlers. A handler
// implementation could be used to intercept calls of all types before sending
// them to the next handler.
// This is different than roundTripper because it handles multiple messages,
// and needs to provide a shutdown callback.
type Handler interface {
Handle(ctx context.Context, msg Message) (Message, error)
Stop(error) error
}
type sessionHandler struct {
s Session
msize int
// TODO(frobnitzem): make use of version to audit messages at this level
}
// SSession returns a handler that transforms messages
// into function calls (dispatching to Session's methods).
// Since the ServeConn function calls the handler from
// gorotines, no concurrency is managed by the handler this
// defined by SSession.
//
// Instead, the Handler simply turns messages into function
// calls on the session.
func SSession(session Session) Handler {
msize, _ := session.Version()
return sessionHandler{session, msize}
}
func (sess sessionHandler) Stop(err error) error {
return sess.s.Stop(err)
}
func (sess sessionHandler) Handle(ctx context.Context,
msg Message) (Message, error) {
session := sess.s
msize := sess.msize
switch msg := msg.(type) {
case MessageTauth:
qid, err := session.Auth(ctx, msg.Afid, msg.Uname, msg.Aname)
if err != nil {
return nil, err
}
return MessageRauth{Qid: qid}, nil
case MessageTattach:
qid, err := session.Attach(ctx, msg.Fid, msg.Afid, msg.Uname, msg.Aname)
if err != nil {
return nil, err
}
return MessageRattach{
Qid: qid,
}, nil
case MessageTwalk:
// TODO(stevvooe): This is one of the places where we need to manage
// fid allocation lifecycle. We need to reserve the fid, then, if this
// call succeeds, we should alloc the fid for future uses. Also need
// to interact correctly with concurrent clunk and the flush of this
// walk message.
qids, err := session.Walk(ctx, msg.Fid, msg.Newfid, msg.Wnames...)
if err != nil {
return nil, err
}
return MessageRwalk{
Qids: qids,
}, nil
case MessageTopen:
qid, iounit, err := session.Open(ctx, msg.Fid, msg.Mode)
if err != nil {
return nil, err
}
return MessageRopen{
Qid: qid,
IOUnit: iounit,
}, nil
case MessageTcreate:
qid, iounit, err := session.Create(ctx, msg.Fid, msg.Name, msg.Perm, msg.Mode)
if err != nil {
return nil, err
}
return MessageRcreate{
Qid: qid,
IOUnit: iounit,
}, nil
case MessageTread:
// Re-write incoming Treads so that handler
// can always respond with a message of the correct msize.
// TODO(frobnitzem): Re-use these read buffers?
count := int(msg.Count)
if count > msize-11 {
count = msize - 11 // TODO: enforce larger msize in negotiation
if count < 0 {
count = 0
}
}
p := make([]byte, count)
n, err := session.Read(ctx, msg.Fid, p, int64(msg.Offset))
if err != nil {
return nil, err
}
return MessageRread{
Data: p[:n],
}, nil
case MessageTwrite:
n, err := session.Write(ctx, msg.Fid, msg.Data, int64(msg.Offset))
if err != nil {
return nil, err
}
return MessageRwrite{
Count: uint32(n),
}, nil
case MessageTclunk:
if err := session.Clunk(ctx, msg.Fid); err != nil {
return nil, err
}
return MessageRclunk{}, nil
case MessageTremove:
if err := session.Remove(ctx, msg.Fid); err != nil {
return nil, err
}
return MessageRremove{}, nil
case MessageTstat:
dir, err := session.Stat(ctx, msg.Fid)
if err != nil {
return nil, err
}
return MessageRstat{
Stat: dir,
}, nil
case MessageTwstat:
if err := session.WStat(ctx, msg.Fid, msg.Stat); err != nil {
return nil, err
}
return MessageRwstat{}, nil
default:
return nil, ErrUnknownMsg
}
}