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  }