github.com/deemoprobe/k8s-first-commit@v0.0.0-20230430165612-a541f1982be3/pkg/proxy/proxier.go (about) 1 /* 2 Copyright 2014 Google Inc. All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 // Simple proxy for tcp connections between a localhost:lport and services that provide 17 // the actual implementations. 18 19 package proxy 20 21 import ( 22 "fmt" 23 "io" 24 "log" 25 "net" 26 "time" 27 28 "github.com/GoogleCloudPlatform/kubernetes/pkg/api" 29 ) 30 31 type Proxier struct { 32 loadBalancer LoadBalancer 33 serviceMap map[string]int 34 } 35 36 func NewProxier(loadBalancer LoadBalancer) *Proxier { 37 return &Proxier{loadBalancer: loadBalancer, serviceMap: make(map[string]int)} 38 } 39 40 func CopyBytes(in, out *net.TCPConn) { 41 log.Printf("Copying from %v <-> %v <-> %v <-> %v", 42 in.RemoteAddr(), in.LocalAddr(), out.LocalAddr(), out.RemoteAddr()) 43 _, err := io.Copy(in, out) 44 if err != nil && err != io.EOF { 45 log.Printf("I/O error: %v", err) 46 } 47 48 in.CloseRead() 49 out.CloseWrite() 50 } 51 52 // Create a bidirectional byte shuffler. Copies bytes to/from each connection. 53 func ProxyConnection(in, out *net.TCPConn) { 54 log.Printf("Creating proxy between %v <-> %v <-> %v <-> %v", 55 in.RemoteAddr(), in.LocalAddr(), out.LocalAddr(), out.RemoteAddr()) 56 go CopyBytes(in, out) 57 go CopyBytes(out, in) 58 } 59 60 func (proxier Proxier) AcceptHandler(service string, listener net.Listener) { 61 for { 62 inConn, err := listener.Accept() 63 if err != nil { 64 log.Printf("Accept failed: %v", err) 65 continue 66 } 67 log.Printf("Accepted connection from: %v to %v", inConn.RemoteAddr(), inConn.LocalAddr()) 68 69 // Figure out where this request should go. 70 endpoint, err := proxier.loadBalancer.LoadBalance(service, inConn.RemoteAddr()) 71 if err != nil { 72 log.Printf("Couldn't find an endpoint for %s %v", service, err) 73 inConn.Close() 74 continue 75 } 76 77 log.Printf("Mapped service %s to endpoint %s", service, endpoint) 78 outConn, err := net.DialTimeout("tcp", endpoint, time.Duration(5)*time.Second) 79 // We basically need to take everything from inConn and send to outConn 80 // and anything coming from outConn needs to be sent to inConn. 81 if err != nil { 82 log.Printf("Dial failed: %v", err) 83 inConn.Close() 84 continue 85 } 86 go ProxyConnection(inConn.(*net.TCPConn), outConn.(*net.TCPConn)) 87 } 88 } 89 90 // AddService starts listening for a new service on a given port. 91 func (proxier Proxier) AddService(service string, port int) error { 92 // Make sure we can start listening on the port before saying all's well. 93 ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 94 if err != nil { 95 return err 96 } 97 log.Printf("Listening for %s on %d", service, port) 98 // If that succeeds, start the accepting loop. 99 go proxier.AcceptHandler(service, ln) 100 return nil 101 } 102 103 func (proxier Proxier) OnUpdate(services []api.Service) { 104 log.Printf("Received update notice: %+v", services) 105 for _, service := range services { 106 port, exists := proxier.serviceMap[service.ID] 107 if !exists || port != service.Port { 108 log.Printf("Adding a new service %s on port %d", service.ID, service.Port) 109 err := proxier.AddService(service.ID, service.Port) 110 if err == nil { 111 proxier.serviceMap[service.ID] = service.Port 112 } else { 113 log.Printf("Failed to start listening for %s on %d", service.ID, service.Port) 114 } 115 } 116 } 117 }