Blame


1 e342de7d 2015-11-11 adrien package p9p
2 e342de7d 2015-11-11 adrien
3 e342de7d 2015-11-11 adrien import (
4 e342de7d 2015-11-11 adrien "fmt"
5 e342de7d 2015-11-11 adrien
6 e342de7d 2015-11-11 adrien "golang.org/x/net/context"
7 e342de7d 2015-11-11 adrien )
8 e342de7d 2015-11-11 adrien
9 e342de7d 2015-11-11 adrien // NOTE(stevvooe): This file contains functions for negotiating version on the
10 e342de7d 2015-11-11 adrien // client and server. There are some nasty details to get right for
11 e342de7d 2015-11-11 adrien // downgrading the connection on the server-side that are not present yet.
12 e342de7d 2015-11-11 adrien // Really, these should be refactored into some sort of channel type that can
13 e342de7d 2015-11-11 adrien // support resets through version messages during the protocol exchange.
14 e342de7d 2015-11-11 adrien
15 e342de7d 2015-11-11 adrien // clientnegotiate negiotiates the protocol version using channel, blocking
16 e342de7d 2015-11-11 adrien // until a response is received. The received value will be the version
17 e342de7d 2015-11-11 adrien // implemented by the server.
18 e342de7d 2015-11-11 adrien func clientnegotiate(ctx context.Context, ch Channel, version string) (string, error) {
19 e342de7d 2015-11-11 adrien req := newFcall(MessageTversion{
20 e342de7d 2015-11-11 adrien MSize: uint32(ch.MSize()),
21 e342de7d 2015-11-11 adrien Version: version,
22 e342de7d 2015-11-11 adrien })
23 e342de7d 2015-11-11 adrien
24 e342de7d 2015-11-11 adrien if err := ch.WriteFcall(ctx, req); err != nil {
25 e342de7d 2015-11-11 adrien return "", err
26 e342de7d 2015-11-11 adrien }
27 e342de7d 2015-11-11 adrien
28 e342de7d 2015-11-11 adrien resp := new(Fcall)
29 e342de7d 2015-11-11 adrien if err := ch.ReadFcall(ctx, resp); err != nil {
30 e342de7d 2015-11-11 adrien return "", err
31 e342de7d 2015-11-11 adrien }
32 e342de7d 2015-11-11 adrien
33 e342de7d 2015-11-11 adrien switch v := resp.Message.(type) {
34 e342de7d 2015-11-11 adrien case MessageRversion:
35 e342de7d 2015-11-11 adrien
36 e342de7d 2015-11-11 adrien if v.Version != version {
37 e342de7d 2015-11-11 adrien // TODO(stevvooe): A stubborn client indeed!
38 e342de7d 2015-11-11 adrien return "", fmt.Errorf("unsupported server version: %v", version)
39 e342de7d 2015-11-11 adrien }
40 e342de7d 2015-11-11 adrien
41 e342de7d 2015-11-11 adrien if int(v.MSize) > ch.MSize() {
42 e342de7d 2015-11-11 adrien // upgrade msize if server differs.
43 e342de7d 2015-11-11 adrien ch.SetMSize(int(v.MSize))
44 e342de7d 2015-11-11 adrien }
45 e342de7d 2015-11-11 adrien
46 e342de7d 2015-11-11 adrien return v.Version, nil
47 e342de7d 2015-11-11 adrien case error:
48 e342de7d 2015-11-11 adrien return "", v
49 e342de7d 2015-11-11 adrien default:
50 e342de7d 2015-11-11 adrien return "", ErrUnexpectedMsg
51 e342de7d 2015-11-11 adrien }
52 e342de7d 2015-11-11 adrien }
53 e342de7d 2015-11-11 adrien
54 e342de7d 2015-11-11 adrien // servernegotiate blocks until a version message is received or a timeout
55 e342de7d 2015-11-11 adrien // occurs. The msize for the tranport will be set from the negotiation. If
56 e342de7d 2015-11-11 adrien // negotiate returns nil, a server may proceed with the connection.
57 e342de7d 2015-11-11 adrien //
58 e342de7d 2015-11-11 adrien // In the future, it might be better to handle the version messages in a
59 e342de7d 2015-11-11 adrien // separate object that manages the session. Each set of version requests
60 e342de7d 2015-11-11 adrien // effectively "reset" a connection, meaning all fids get clunked and all
61 e342de7d 2015-11-11 adrien // outstanding IO is aborted. This is probably slightly racy, in practice with
62 e342de7d 2015-11-11 adrien // a misbehaved client. The main issue is that we cannot tell which session
63 e342de7d 2015-11-11 adrien // messages belong to.
64 e342de7d 2015-11-11 adrien func servernegotiate(ctx context.Context, ch Channel, version string) error {
65 e342de7d 2015-11-11 adrien // wait for the version message over the transport.
66 e342de7d 2015-11-11 adrien req := new(Fcall)
67 e342de7d 2015-11-11 adrien if err := ch.ReadFcall(ctx, req); err != nil {
68 e342de7d 2015-11-11 adrien return err
69 e342de7d 2015-11-11 adrien }
70 e342de7d 2015-11-11 adrien
71 e342de7d 2015-11-11 adrien mv, ok := req.Message.(MessageTversion)
72 e342de7d 2015-11-11 adrien if !ok {
73 e342de7d 2015-11-11 adrien return fmt.Errorf("expected version message: %v", mv)
74 e342de7d 2015-11-11 adrien }
75 e342de7d 2015-11-11 adrien
76 e342de7d 2015-11-11 adrien respmsg := MessageRversion{
77 e342de7d 2015-11-11 adrien Version: version,
78 e342de7d 2015-11-11 adrien }
79 e342de7d 2015-11-11 adrien
80 e342de7d 2015-11-11 adrien if mv.Version != version {
81 e342de7d 2015-11-11 adrien // TODO(stevvooe): Not the best place to do version handling. We need
82 e342de7d 2015-11-11 adrien // to have a way to pass supported versions into this method then have
83 e342de7d 2015-11-11 adrien // it return the actual version. For now, respond with unknown for
84 e342de7d 2015-11-11 adrien // anything that doesn't match the provided version string.
85 e342de7d 2015-11-11 adrien respmsg.Version = "unknown"
86 e342de7d 2015-11-11 adrien }
87 e342de7d 2015-11-11 adrien
88 e342de7d 2015-11-11 adrien if int(mv.MSize) < ch.MSize() {
89 e342de7d 2015-11-11 adrien // if the server msize is too large, use the client's suggested msize.
90 e342de7d 2015-11-11 adrien ch.SetMSize(int(mv.MSize))
91 e342de7d 2015-11-11 adrien respmsg.MSize = mv.MSize
92 e342de7d 2015-11-11 adrien } else {
93 e342de7d 2015-11-11 adrien respmsg.MSize = uint32(ch.MSize())
94 e342de7d 2015-11-11 adrien }
95 e342de7d 2015-11-11 adrien
96 e342de7d 2015-11-11 adrien resp := newFcall(respmsg)
97 e342de7d 2015-11-11 adrien if err := ch.WriteFcall(ctx, resp); err != nil {
98 e342de7d 2015-11-11 adrien return err
99 e342de7d 2015-11-11 adrien }
100 e342de7d 2015-11-11 adrien
101 e342de7d 2015-11-11 adrien if respmsg.Version == "unknown" {
102 e342de7d 2015-11-11 adrien return fmt.Errorf("bad version negotiation")
103 e342de7d 2015-11-11 adrien }
104 e342de7d 2015-11-11 adrien
105 e342de7d 2015-11-11 adrien return nil
106 e342de7d 2015-11-11 adrien }