azure-container-networking/common/listener.go

202 строки
5.3 KiB
Go

// Copyright 2017 Microsoft. All rights reserved.
// MIT License
package common
import (
"crypto/tls"
"encoding/json"
"fmt"
"net"
"net/http"
"net/url"
"os"
"github.com/Azure/azure-container-networking/log"
localtls "github.com/Azure/azure-container-networking/server/tls"
)
// Listener represents an HTTP listener.
type Listener struct {
URL *url.URL
protocol string
localAddress string
endpoints []string
active bool
l net.Listener
securelistener net.Listener
mux *http.ServeMux
}
// NewListener creates a new Listener.
func NewListener(u *url.URL) (*Listener, error) {
listener := Listener{
URL: u,
protocol: u.Scheme,
localAddress: u.Host + u.Path,
}
listener.mux = http.NewServeMux()
return &listener, nil
}
func GetTlsConfig(tlsSettings localtls.TlsSettings) (*tls.Config, error) {
tlsCertRetriever, err := localtls.GetTlsCertificateRetriever(tlsSettings)
if err != nil {
return nil, fmt.Errorf("Failed to get certificate retriever %+v", err)
}
leafCertificate, err := tlsCertRetriever.GetCertificate()
if err != nil {
return nil, fmt.Errorf("Failed to get certificate %+v", err)
}
if leafCertificate == nil {
return nil, fmt.Errorf("Certificate retrival returned empty %+v", err)
}
privateKey, err := tlsCertRetriever.GetPrivateKey()
if err != nil {
return nil, fmt.Errorf("Failed to get certificate private key %+v", err)
}
tlsCert := tls.Certificate{
Certificate: [][]byte{leafCertificate.Raw},
PrivateKey: privateKey,
Leaf: leafCertificate,
}
tlsConfig := &tls.Config{
MaxVersion: tls.VersionTLS12,
MinVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{
tlsCert,
},
}
return tlsConfig, nil
}
// Start creates the listener socket and starts the HTTPS server.
func (listener *Listener) StartTLS(errChan chan<- error, tlsSettings localtls.TlsSettings) error {
tlsConfig, err := GetTlsConfig(tlsSettings)
if err != nil {
log.Printf("[Listener] Failed to compose Tls Configuration with errror: %+v", err)
return err
}
server := http.Server{
TLSConfig: tlsConfig,
Handler: listener.mux,
}
// listen on a seperate endpoint for secure tls connections
listener.securelistener, err = net.Listen(listener.protocol, tlsSettings.TLSEndpoint)
if err != nil {
log.Printf("[Listener] Failed to listen on TlsEndpoint: %+v", err)
return err
}
log.Printf("[Listener] Started listening on tls endpoint %s.", tlsSettings.TLSEndpoint)
// Launch goroutine for servicing https requests
go func() {
errChan <- server.ServeTLS(listener.securelistener, "", "")
}()
listener.active = true
return nil
}
// Start creates the listener socket and starts the HTTP server.
func (listener *Listener) Start(errChan chan<- error) error {
var err error
// Succeed early if no socket was requested.
if listener.localAddress == "null" {
return nil
}
listener.l, err = net.Listen(listener.protocol, listener.localAddress)
if err != nil {
log.Printf("[Listener] Failed to listen: %+v", err)
return err
}
log.Printf("[Listener] Started listening on %s.", listener.localAddress)
// Launch goroutine for servicing requests.
go func() {
errChan <- http.Serve(listener.l, listener.mux)
}()
listener.active = true
return nil
}
// Stop stops listening for requests.
func (listener *Listener) Stop() {
// Ignore if not active.
if !listener.active {
return
}
listener.active = false
// Stop servicing requests.
listener.l.Close()
if listener.securelistener != nil {
// Stop servicing requests on secure listener
listener.securelistener.Close()
}
// Delete the unix socket.
if listener.protocol == "unix" {
os.Remove(listener.localAddress)
}
log.Printf("[Listener] Stopped listening on %s", listener.localAddress)
}
// GetMux returns the HTTP mux for the listener.
func (listener *Listener) GetMux() *http.ServeMux {
return listener.mux
}
// GetEndpoints returns the list of registered protocol endpoints.
func (listener *Listener) GetEndpoints() []string {
return listener.endpoints
}
// AddEndpoint registers a protocol endpoint.
func (listener *Listener) AddEndpoint(endpoint string) {
listener.endpoints = append(listener.endpoints, endpoint)
}
// AddHandler registers a protocol handler.
func (listener *Listener) AddHandler(path string, handler http.HandlerFunc) {
listener.mux.HandleFunc(path, handler)
}
// Decode receives and decodes JSON payload to a request.
func (listener *Listener) Decode(w http.ResponseWriter, r *http.Request, request interface{}) error {
var err error
if r.Body == nil {
err = fmt.Errorf("Request body is empty")
} else {
err = json.NewDecoder(r.Body).Decode(request)
}
if err != nil {
http.Error(w, "Failed to decode request: "+err.Error(), http.StatusBadRequest)
log.Printf("[Listener] Failed to decode request: %v\n", err.Error())
}
return err
}
// Encode encodes and sends a response as JSON payload.
func (listener *Listener) Encode(w http.ResponseWriter, response interface{}) error {
// Set the content type as application json
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
err := json.NewEncoder(w).Encode(response)
if err != nil {
http.Error(w, "Failed to encode response: "+err.Error(), http.StatusInternalServerError)
log.Printf("[Listener] Failed to encode response: %v\n", err.Error())
}
return err
}