1 // Copyright 2012 Google Inc. All Rights Reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
33 MaxIdleDuration time
.Duration
34 PollUpdateInterval time
.Duration
41 func (p
*Proxy
) Run() error
{
42 hl
, err
:= net
.Listen("tcp", "127.0.0.1:0")
44 return fmt
.Errorf("http listen failed: %v", err
)
48 hsl
, err
:= net
.Listen("tcp", "127.0.0.1:0")
50 return fmt
.Errorf("https listen failed: %v", err
)
54 p
.ul
, err
= DefaultSocket
.Listen()
56 c
, derr
:= DefaultSocket
.Dial()
59 fmt
.Println("OK\nA proxy is already running... exiting")
61 } else if e
, ok
:= derr
.(*net
.OpError
); ok
&& e
.Err
== syscall
.ECONNREFUSED
{
62 // Nothing is listening on the socket, unlink it and try again.
63 syscall
.Unlink(DefaultSocket
.Path())
64 p
.ul
, err
= DefaultSocket
.Listen()
67 return fmt
.Errorf("unix listen failed on %v: %v", DefaultSocket
.Path(), err
)
74 p
.httpAddr
= hl
.Addr().String()
75 p
.httpsAddr
= hsl
.Addr().String()
76 fmt
.Printf("OK\nListening on unix socket=%v http=%v https=%v\n",
77 p
.ul
.Addr(), p
.httpAddr
, p
.httpsAddr
)
79 result
:= make(chan error
, 2)
80 go p
.serveUnix(result
)
82 result
<- http
.Serve(hl
, &httputil
.ReverseProxy
{
83 FlushInterval
: 500 * time
.Millisecond
,
84 Director
: func(r
*http
.Request
) {},
88 result
<- http
.Serve(hsl
, &httputil
.ReverseProxy
{
89 FlushInterval
: 500 * time
.Millisecond
,
90 Director
: func(r
*http
.Request
) {
91 r
.URL
.Scheme
= "https"
98 type socketContext
struct {
104 func (sc
*socketContext
) Done() {
106 defer sc
.mutex
.Unlock()
111 func (p
*Proxy
) serveUnix(result
chan<- error
) {
112 sockCtx
:= &socketContext
{}
113 go p
.closeOnIdle(sockCtx
)
118 uconn
, err
= p
.ul
.Accept()
120 err
= fmt
.Errorf("accept failed: %v", err
)
124 go p
.handleUnixConn(sockCtx
, uconn
)
130 func (p
*Proxy
) handleUnixConn(sockCtx
*socketContext
, uconn net
.Conn
) {
133 data
:= []byte(fmt
.Sprintf("%v\n%v", p
.httpsAddr
, p
.httpAddr
))
134 uconn
.SetDeadline(time
.Now().Add(5 * time
.Second
))
135 for i
:= 0; i
< 2; i
++ {
136 if n
, err
:= uconn
.Write(data
); err
!= nil {
137 log
.Printf("error sending http addresses: %+v\n", err
)
139 } else if n
!= len(data
) {
140 log
.Printf("sent %d data bytes, wanted %d\n", n
, len(data
))
143 if _
, err
:= uconn
.Read([]byte{0, 0, 0, 0}); err
!= nil {
144 log
.Printf("error waiting for Ack: %+v\n", err
)
148 // Wait without a deadline for the client to finish via EOF
149 uconn
.SetDeadline(time
.Time
{})
150 uconn
.Read([]byte{0, 0, 0, 0})
153 func (p
*Proxy
) closeOnIdle(sockCtx
*socketContext
) {
154 for d
:= p
.MaxIdleDuration
; d
> 0; {
158 if d
= sockCtx
.last
.Add(p
.MaxIdleDuration
).Sub(time
.Now()); d
<= 0 {
159 log
.Println("graceful shutdown from idle timeout")
162 sockCtx
.mutex
.Unlock()
166 func (p
*Proxy
) closeOnUpdate() {
168 time
.Sleep(p
.PollUpdateInterval
)
169 if out
, err
:= exec
.Command(os
.Args
[0], "--print_label").Output(); err
!= nil {
170 log
.Printf("error polling for updated binary: %v\n", err
)
171 } else if s
:= string(out
[:len(out
)-1]); p
.BuildLabel
!= s
{
172 log
.Printf("graceful shutdown from updated binary: %q --> %q\n", p
.BuildLabel
, s
)
179 func (p
*Proxy
) closeOnSignal() {
180 ch
:= make(chan os
.Signal
, 10)
181 signal
.Notify(ch
, os
.Interrupt
, os
.Kill
, os
.Signal(syscall
.SIGTERM
), os
.Signal(syscall
.SIGHUP
))
185 case os
.Signal(syscall
.SIGHUP
):
186 log
.Printf("graceful shutdown from signal: %v\n", sig
)
188 log
.Fatalf("exiting from signal: %v\n", sig
)