Blame


1 499f8c59 2015-10-27 stephen.d package p9pnew
2 499f8c59 2015-10-27 stephen.d
3 96ad2b22 2015-10-28 stephen.d import (
4 96ad2b22 2015-10-28 stephen.d "log"
5 96ad2b22 2015-10-28 stephen.d "net"
6 40d4a02d 2015-11-03 stephen.d "time"
7 499f8c59 2015-10-27 stephen.d
8 96ad2b22 2015-10-28 stephen.d "golang.org/x/net/context"
9 96ad2b22 2015-10-28 stephen.d )
10 96ad2b22 2015-10-28 stephen.d
11 499f8c59 2015-10-27 stephen.d // Serve the 9p session over the provided network connection.
12 e6bcde66 2015-10-29 stephen.d func Serve(ctx context.Context, conn net.Conn, session Session) {
13 40d4a02d 2015-11-03 stephen.d const msize = 64 << 10
14 40d4a02d 2015-11-03 stephen.d const vers = "9P2000"
15 40d4a02d 2015-11-03 stephen.d
16 40d4a02d 2015-11-03 stephen.d ch := newChannel(conn, codec9p{}, msize)
17 40d4a02d 2015-11-03 stephen.d
18 40d4a02d 2015-11-03 stephen.d negctx, cancel := context.WithTimeout(ctx, 1*time.Second)
19 40d4a02d 2015-11-03 stephen.d defer cancel()
20 40d4a02d 2015-11-03 stephen.d
21 40d4a02d 2015-11-03 stephen.d // TODO(stevvooe): For now, we negotiate here. It probably makes sense to
22 40d4a02d 2015-11-03 stephen.d // do this outside of this function and then pass in a ready made channel.
23 40d4a02d 2015-11-03 stephen.d // We are not really ready to export the channel type yet.
24 40d4a02d 2015-11-03 stephen.d
25 3bf22e58 2015-11-04 stephen.d if err := servernegotiate(negctx, ch, vers); err != nil {
26 40d4a02d 2015-11-03 stephen.d // TODO(stevvooe): Need better error handling and retry support here.
27 40d4a02d 2015-11-03 stephen.d // For now, we silently ignore the failure.
28 40d4a02d 2015-11-03 stephen.d log.Println("error negotiating version:", err)
29 40d4a02d 2015-11-03 stephen.d return
30 40d4a02d 2015-11-03 stephen.d }
31 40d4a02d 2015-11-03 stephen.d
32 e6bcde66 2015-10-29 stephen.d s := &server{
33 e6bcde66 2015-10-29 stephen.d ctx: ctx,
34 40d4a02d 2015-11-03 stephen.d ch: ch,
35 40d4a02d 2015-11-03 stephen.d handler: &dispatcher{session: session},
36 40d4a02d 2015-11-03 stephen.d closed: make(chan struct{}),
37 e6bcde66 2015-10-29 stephen.d }
38 e6bcde66 2015-10-29 stephen.d
39 e6bcde66 2015-10-29 stephen.d s.run()
40 499f8c59 2015-10-27 stephen.d }
41 96ad2b22 2015-10-28 stephen.d
42 96ad2b22 2015-10-28 stephen.d type server struct {
43 96ad2b22 2015-10-28 stephen.d ctx context.Context
44 96ad2b22 2015-10-28 stephen.d session Session
45 3bf22e58 2015-11-04 stephen.d ch Channel
46 40d4a02d 2015-11-03 stephen.d handler handler
47 e6bcde66 2015-10-29 stephen.d closed chan struct{}
48 96ad2b22 2015-10-28 stephen.d }
49 96ad2b22 2015-10-28 stephen.d
50 40d4a02d 2015-11-03 stephen.d type activeTag struct {
51 40d4a02d 2015-11-03 stephen.d ctx context.Context
52 40d4a02d 2015-11-03 stephen.d request *Fcall
53 40d4a02d 2015-11-03 stephen.d cancel context.CancelFunc
54 40d4a02d 2015-11-03 stephen.d responded bool // true, if some response was sent (Response or Rflush/Rerror)
55 40d4a02d 2015-11-03 stephen.d }
56 40d4a02d 2015-11-03 stephen.d
57 96ad2b22 2015-10-28 stephen.d func (s *server) run() {
58 40d4a02d 2015-11-03 stephen.d tags := map[Tag]*activeTag{} // active requests
59 96ad2b22 2015-10-28 stephen.d
60 e6bcde66 2015-10-29 stephen.d log.Println("server.run()")
61 e6bcde66 2015-10-29 stephen.d for {
62 e6bcde66 2015-10-29 stephen.d select {
63 e6bcde66 2015-10-29 stephen.d case <-s.ctx.Done():
64 e6bcde66 2015-10-29 stephen.d log.Println("server: shutdown")
65 e6bcde66 2015-10-29 stephen.d return
66 e6bcde66 2015-10-29 stephen.d case <-s.closed:
67 e6bcde66 2015-10-29 stephen.d default:
68 e6bcde66 2015-10-29 stephen.d }
69 e6bcde66 2015-10-29 stephen.d
70 40d4a02d 2015-11-03 stephen.d // BUG(stevvooe): This server blocks on reads, calls to handlers and
71 40d4a02d 2015-11-03 stephen.d // write, effectively single tracking fcalls through a target
72 40d4a02d 2015-11-03 stephen.d // dispatcher. There is no reason we couldn't parallelize these
73 40d4a02d 2015-11-03 stephen.d // requests out to the dispatcher to get massive performance
74 40d4a02d 2015-11-03 stephen.d // improvements.
75 e6bcde66 2015-10-29 stephen.d
76 e6bcde66 2015-10-29 stephen.d log.Println("server:", "wait")
77 40d4a02d 2015-11-03 stephen.d req := new(Fcall)
78 3bf22e58 2015-11-04 stephen.d if err := s.ch.ReadFcall(s.ctx, req); err != nil {
79 40d4a02d 2015-11-03 stephen.d log.Println("server: error reading fcall", err)
80 e6bcde66 2015-10-29 stephen.d continue
81 e6bcde66 2015-10-29 stephen.d }
82 e6bcde66 2015-10-29 stephen.d
83 40d4a02d 2015-11-03 stephen.d if _, ok := tags[req.Tag]; ok {
84 40d4a02d 2015-11-03 stephen.d resp := newErrorFcall(req.Tag, ErrDuptag)
85 3bf22e58 2015-11-04 stephen.d if err := s.ch.WriteFcall(s.ctx, resp); err != nil {
86 40d4a02d 2015-11-03 stephen.d log.Printf("error sending duplicate tag response: %v", err)
87 e6bcde66 2015-10-29 stephen.d }
88 e6bcde66 2015-10-29 stephen.d continue
89 e6bcde66 2015-10-29 stephen.d }
90 e6bcde66 2015-10-29 stephen.d
91 40d4a02d 2015-11-03 stephen.d // handle flush calls. The tag never makes it into active from here.
92 40d4a02d 2015-11-03 stephen.d if mf, ok := req.Message.(MessageTflush); ok {
93 40d4a02d 2015-11-03 stephen.d log.Println("flushing message", mf.Oldtag)
94 e6bcde66 2015-10-29 stephen.d
95 40d4a02d 2015-11-03 stephen.d // check if we have actually know about the requested flush
96 40d4a02d 2015-11-03 stephen.d active, ok := tags[mf.Oldtag]
97 40d4a02d 2015-11-03 stephen.d if ok {
98 40d4a02d 2015-11-03 stephen.d active.cancel() // cancel the context
99 e6bcde66 2015-10-29 stephen.d
100 40d4a02d 2015-11-03 stephen.d resp := newFcall(MessageRflush{})
101 40d4a02d 2015-11-03 stephen.d resp.Tag = req.Tag
102 3bf22e58 2015-11-04 stephen.d if err := s.ch.WriteFcall(s.ctx, resp); err != nil {
103 40d4a02d 2015-11-03 stephen.d log.Printf("error responding to flush: %v", err)
104 40d4a02d 2015-11-03 stephen.d }
105 40d4a02d 2015-11-03 stephen.d active.responded = true
106 40d4a02d 2015-11-03 stephen.d } else {
107 40d4a02d 2015-11-03 stephen.d resp := newErrorFcall(req.Tag, ErrUnknownTag)
108 3bf22e58 2015-11-04 stephen.d if err := s.ch.WriteFcall(s.ctx, resp); err != nil {
109 40d4a02d 2015-11-03 stephen.d log.Printf("error responding to flush: %v", err)
110 40d4a02d 2015-11-03 stephen.d }
111 40d4a02d 2015-11-03 stephen.d }
112 96ad2b22 2015-10-28 stephen.d
113 40d4a02d 2015-11-03 stephen.d continue
114 96ad2b22 2015-10-28 stephen.d }
115 96ad2b22 2015-10-28 stephen.d
116 40d4a02d 2015-11-03 stephen.d // TODO(stevvooe): Add handler timeout here, as well, if we desire.
117 e6bcde66 2015-10-29 stephen.d
118 40d4a02d 2015-11-03 stephen.d // Allows us to signal handlers to cancel processing of the fcall
119 40d4a02d 2015-11-03 stephen.d // through context.
120 40d4a02d 2015-11-03 stephen.d ctx, cancel := context.WithCancel(s.ctx)
121 e6bcde66 2015-10-29 stephen.d
122 40d4a02d 2015-11-03 stephen.d tags[req.Tag] = &activeTag{
123 40d4a02d 2015-11-03 stephen.d ctx: ctx,
124 40d4a02d 2015-11-03 stephen.d request: req,
125 40d4a02d 2015-11-03 stephen.d cancel: cancel,
126 e6bcde66 2015-10-29 stephen.d }
127 e6bcde66 2015-10-29 stephen.d
128 40d4a02d 2015-11-03 stephen.d resp, err := s.handler.handle(ctx, req)
129 97423e8b 2015-10-29 stephen.d if err != nil {
130 40d4a02d 2015-11-03 stephen.d // all handler errors are forwarded as protocol errors.
131 40d4a02d 2015-11-03 stephen.d resp = newErrorFcall(req.Tag, err)
132 97423e8b 2015-10-29 stephen.d }
133 40d4a02d 2015-11-03 stephen.d resp.Tag = req.Tag
134 97423e8b 2015-10-29 stephen.d
135 40d4a02d 2015-11-03 stephen.d if err := ctx.Err(); err != nil {
136 40d4a02d 2015-11-03 stephen.d // NOTE(stevvooe): We aren't really getting our moneys worth for
137 40d4a02d 2015-11-03 stephen.d // how this is being handled. We really need to dispatch each
138 40d4a02d 2015-11-03 stephen.d // request handler to a separate thread.
139 97423e8b 2015-10-29 stephen.d
140 40d4a02d 2015-11-03 stephen.d // the context was canceled for some reason, perhaps timeout or
141 40d4a02d 2015-11-03 stephen.d // due to a flush call. We treat this as a condition where a
142 40d4a02d 2015-11-03 stephen.d // response should not be sent.
143 40d4a02d 2015-11-03 stephen.d log.Println("context error:", err)
144 40d4a02d 2015-11-03 stephen.d continue
145 97423e8b 2015-10-29 stephen.d }
146 97423e8b 2015-10-29 stephen.d
147 40d4a02d 2015-11-03 stephen.d if !tags[req.Tag].responded {
148 3bf22e58 2015-11-04 stephen.d if err := s.ch.WriteFcall(ctx, resp); err != nil {
149 40d4a02d 2015-11-03 stephen.d log.Println("server: error writing fcall:", err)
150 40d4a02d 2015-11-03 stephen.d continue
151 40d4a02d 2015-11-03 stephen.d }
152 97423e8b 2015-10-29 stephen.d }
153 97423e8b 2015-10-29 stephen.d
154 40d4a02d 2015-11-03 stephen.d delete(tags, req.Tag)
155 96ad2b22 2015-10-28 stephen.d }
156 96ad2b22 2015-10-28 stephen.d }