Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Vanadium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package xproxyd |
| 6 | |
| 7 | import ( |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 8 | "fmt" |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 9 | "io" |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 10 | "sync" |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 11 | |
| 12 | "v.io/v23" |
| 13 | "v.io/v23/context" |
| 14 | "v.io/v23/flow" |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 15 | "v.io/v23/flow/message" |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 16 | "v.io/v23/naming" |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 17 | ) |
| 18 | |
| 19 | // TODO(suharshs): Make sure that we don't leak any goroutines. |
| 20 | |
| 21 | type proxy struct { |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 22 | m flow.Manager |
| 23 | mu sync.Mutex |
| 24 | proxyEndpoints []naming.Endpoint |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 25 | } |
| 26 | |
Suharsh Sivakumar | e0feb27 | 2015-09-14 18:03:48 -0700 | [diff] [blame] | 27 | func New(ctx *context.T) (*proxy, *context.T, error) { |
| 28 | ctx, mgr, err := v23.ExperimentalWithNewFlowManager(ctx) |
| 29 | if err != nil { |
| 30 | return nil, nil, err |
| 31 | } |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 32 | p := &proxy{ |
Suharsh Sivakumar | e0feb27 | 2015-09-14 18:03:48 -0700 | [diff] [blame] | 33 | m: mgr, |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 34 | } |
| 35 | for _, addr := range v23.GetListenSpec(ctx).Addrs { |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 36 | if addr.Protocol == "v23" { |
| 37 | ep, err := v23.NewEndpoint(addr.Address) |
| 38 | if err != nil { |
Suharsh Sivakumar | e0feb27 | 2015-09-14 18:03:48 -0700 | [diff] [blame] | 39 | return nil, nil, err |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 40 | } |
| 41 | f, err := p.m.Dial(ctx, ep, proxyBlessingsForPeer{}.run) |
| 42 | if err != nil { |
Suharsh Sivakumar | e0feb27 | 2015-09-14 18:03:48 -0700 | [diff] [blame] | 43 | return nil, nil, err |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 44 | } |
| 45 | // Send a byte telling the acceptor that we are a proxy. |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 46 | if err := writeMessage(ctx, &message.MultiProxyRequest{}, f); err != nil { |
Suharsh Sivakumar | e0feb27 | 2015-09-14 18:03:48 -0700 | [diff] [blame] | 47 | return nil, nil, err |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 48 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 49 | msg, err := readMessage(ctx, f) |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 50 | if err != nil { |
Suharsh Sivakumar | e0feb27 | 2015-09-14 18:03:48 -0700 | [diff] [blame] | 51 | return nil, nil, err |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 52 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 53 | m, ok := msg.(*message.ProxyResponse) |
| 54 | if !ok { |
Suharsh Sivakumar | e0feb27 | 2015-09-14 18:03:48 -0700 | [diff] [blame] | 55 | return nil, nil, NewErrUnexpectedMessage(ctx, fmt.Sprintf("%t", m)) |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 56 | } |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 57 | p.mu.Lock() |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 58 | p.proxyEndpoints = append(p.proxyEndpoints, m.Endpoints...) |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 59 | p.mu.Unlock() |
| 60 | } else if err := p.m.Listen(ctx, addr.Protocol, addr.Address); err != nil { |
Suharsh Sivakumar | e0feb27 | 2015-09-14 18:03:48 -0700 | [diff] [blame] | 61 | return nil, nil, err |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 62 | } |
| 63 | } |
| 64 | go p.listenLoop(ctx) |
Suharsh Sivakumar | e0feb27 | 2015-09-14 18:03:48 -0700 | [diff] [blame] | 65 | return p, ctx, nil |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 66 | } |
| 67 | |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 68 | func (p *proxy) ListeningEndpoints() []naming.Endpoint { |
| 69 | return p.m.ListeningEndpoints() |
| 70 | } |
| 71 | |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 72 | func (p *proxy) listenLoop(ctx *context.T) { |
| 73 | for { |
| 74 | f, err := p.m.Accept(ctx) |
| 75 | if err != nil { |
| 76 | ctx.Infof("p.m.Accept failed: %v", err) |
| 77 | break |
| 78 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 79 | msg, err := readMessage(ctx, f) |
| 80 | if err != nil { |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 81 | ctx.Errorf("reading type byte failed: %v", err) |
| 82 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 83 | switch m := msg.(type) { |
| 84 | case *message.Setup: |
| 85 | err = p.startRouting(ctx, f, m) |
| 86 | case *message.MultiProxyRequest: |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 87 | err = p.replyToProxy(ctx, f) |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 88 | case *message.ProxyServerRequest: |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 89 | err = p.replyToServer(ctx, f) |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 90 | default: |
| 91 | continue |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 92 | } |
| 93 | if err != nil { |
| 94 | ctx.Errorf("failed to handle incoming connection: %v", err) |
| 95 | } |
| 96 | } |
| 97 | } |
| 98 | |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 99 | func (p *proxy) startRouting(ctx *context.T, f flow.Flow, m *message.Setup) error { |
| 100 | fout, err := p.dialNextHop(ctx, f, m) |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 101 | if err != nil { |
| 102 | return err |
| 103 | } |
| 104 | go p.forwardLoop(ctx, f, fout) |
| 105 | go p.forwardLoop(ctx, fout, f) |
| 106 | return nil |
| 107 | } |
| 108 | |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 109 | func (p *proxy) forwardLoop(ctx *context.T, fin, fout flow.Flow) { |
| 110 | for { |
| 111 | _, err := io.Copy(fin, fout) |
| 112 | if err == io.EOF { |
| 113 | return |
| 114 | } else if err != nil { |
| 115 | ctx.Errorf("f.Read failed: %v", err) |
| 116 | return |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 121 | func (p *proxy) dialNextHop(ctx *context.T, f flow.Flow, m *message.Setup) (flow.Flow, error) { |
| 122 | var ( |
| 123 | rid naming.RoutingID |
| 124 | ep naming.Endpoint |
| 125 | err error |
| 126 | ) |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 127 | if routes := m.PeerRemoteEndpoint.Routes(); len(routes) > 0 { |
| 128 | if err := rid.FromString(routes[0]); err != nil { |
| 129 | return nil, err |
| 130 | } |
| 131 | // Make an endpoint with the correct routingID to dial out. All other fields |
| 132 | // do not matter. |
| 133 | // TODO(suharshs): Make sure that the routingID from the route belongs to a |
| 134 | // connection that is stored in the manager's cache. (i.e. a Server has connected |
| 135 | // with the routingID before) |
| 136 | if ep, err = setEndpointRoutingID(m.PeerRemoteEndpoint, rid); err != nil { |
| 137 | return nil, err |
| 138 | } |
| 139 | // Remove the read route from the setup message endpoint. |
| 140 | if m.PeerRemoteEndpoint, err = setEndpointRoutes(m.PeerRemoteEndpoint, routes[1:]); err != nil { |
| 141 | return nil, err |
| 142 | } |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 143 | } else { |
| 144 | ep = m.PeerRemoteEndpoint |
| 145 | } |
| 146 | fout, err := p.m.Dial(ctx, ep, proxyBlessingsForPeer{}.run) |
Suharsh Sivakumar | a2e2b74 | 2015-08-26 15:54:40 -0700 | [diff] [blame] | 147 | if err != nil { |
| 148 | return nil, err |
| 149 | } |
| 150 | // Write the setup message back onto the flow for the next hop to read. |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 151 | return fout, writeMessage(ctx, m, fout) |
Suharsh Sivakumar | a2e2b74 | 2015-08-26 15:54:40 -0700 | [diff] [blame] | 152 | } |
| 153 | |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 154 | func (p *proxy) replyToServer(ctx *context.T, f flow.Flow) error { |
| 155 | rid := f.Conn().RemoteEndpoint().RoutingID() |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 156 | eps, err := p.returnEndpoints(ctx, rid, "") |
Suharsh Sivakumar | a2e2b74 | 2015-08-26 15:54:40 -0700 | [diff] [blame] | 157 | if err != nil { |
| 158 | return err |
| 159 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 160 | return writeMessage(ctx, &message.ProxyResponse{Endpoints: eps}, f) |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 161 | } |
| 162 | |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 163 | func (p *proxy) replyToProxy(ctx *context.T, f flow.Flow) error { |
| 164 | // Add the routing id of the incoming proxy to the routes. The routing id of the |
| 165 | // returned endpoint doesn't matter because it will eventually be replaced |
| 166 | // by a server's rid by some later proxy. |
| 167 | // TODO(suharshs): Use a local route instead of this global routingID. |
| 168 | rid := f.Conn().RemoteEndpoint().RoutingID() |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 169 | eps, err := p.returnEndpoints(ctx, naming.NullRoutingID, rid.String()) |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 170 | if err != nil { |
| 171 | return err |
| 172 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 173 | return writeMessage(ctx, &message.ProxyResponse{Endpoints: eps}, f) |
Suharsh Sivakumar | fb4af95 | 2015-08-21 17:51:01 -0700 | [diff] [blame] | 174 | } |
Suharsh Sivakumar | a2e2b74 | 2015-08-26 15:54:40 -0700 | [diff] [blame] | 175 | |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 176 | func (p *proxy) returnEndpoints(ctx *context.T, rid naming.RoutingID, route string) ([]naming.Endpoint, error) { |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 177 | p.mu.Lock() |
| 178 | eps := append(p.m.ListeningEndpoints(), p.proxyEndpoints...) |
| 179 | p.mu.Unlock() |
| 180 | if len(eps) == 0 { |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 181 | return nil, NewErrNotListening(ctx) |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 182 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 183 | for idx, ep := range eps { |
| 184 | var err error |
| 185 | if rid != naming.NullRoutingID { |
| 186 | ep, err = setEndpointRoutingID(ep, rid) |
| 187 | if err != nil { |
| 188 | return nil, err |
| 189 | } |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 190 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 191 | if len(route) > 0 { |
| 192 | var cp []string |
| 193 | cp = append(cp, ep.Routes()...) |
| 194 | cp = append(cp, route) |
| 195 | ep, err = setEndpointRoutes(ep, cp) |
| 196 | if err != nil { |
| 197 | return nil, err |
| 198 | } |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 199 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 200 | eps[idx] = ep |
Suharsh Sivakumar | 6734a79 | 2015-09-04 12:39:15 -0700 | [diff] [blame] | 201 | } |
Suharsh Sivakumar | 9814377 | 2015-09-10 11:40:53 -0700 | [diff] [blame] | 202 | return eps, nil |
Suharsh Sivakumar | a2e2b74 | 2015-08-26 15:54:40 -0700 | [diff] [blame] | 203 | } |