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