github.com/google/martian/v3@v3.3.3/trafficshape/listener.go (about) 1 // Copyright 2015 Google Inc. All rights reserved. 2 // 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 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 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. 14 15 package trafficshape 16 17 import ( 18 "net" 19 "sync" 20 "time" 21 22 "github.com/google/martian/v3/log" 23 ) 24 25 // DefaultBitrate represents the bitrate that will be for all url regexs for which a shape 26 // has not been specified. 27 var DefaultBitrate int64 = 500000000000 // 500Gbps (unlimited) 28 29 // ErrForceClose is an error that communicates the need to close the connection. 30 type ErrForceClose struct { 31 message string 32 } 33 34 func (efc *ErrForceClose) Error() string { 35 return efc.message 36 } 37 38 // urlShape contains a rw lock protected shape of a url_regex. 39 type urlShape struct { 40 sync.RWMutex 41 Shape *Shape 42 } 43 44 // urlShapes contains a rw lock protected map of url regexs to their URLShapes. 45 type urlShapes struct { 46 sync.RWMutex 47 M map[string]*urlShape 48 LastModifiedTime time.Time 49 } 50 51 // Buckets contains the read and write buckets for a url_regex. 52 type Buckets struct { 53 ReadBucket *Bucket 54 WriteBucket *Bucket 55 } 56 57 // NewBuckets returns a *Buckets with the specified up and down bandwidths. 58 func NewBuckets(up int64, down int64) *Buckets { 59 return &Buckets{ 60 ReadBucket: NewBucket(up, time.Second), 61 WriteBucket: NewBucket(down, time.Second), 62 } 63 } 64 65 // ThrottleContext represents whether we are currently in a throttle interval for a particular 66 // url_regex. If ThrottleNow is true, only then will the current throttle 'Bandwidth' be set 67 // correctly. 68 type ThrottleContext struct { 69 ThrottleNow bool 70 Bandwidth int64 71 } 72 73 // NextActionInfo represents whether there is an upcoming action. Only if ActionNext is true will the 74 // Index and ByteOffset be set correctly. 75 type NextActionInfo struct { 76 ActionNext bool 77 Index int64 78 ByteOffset int64 79 } 80 81 // Context represents the current information that is needed while writing back to the client. 82 // Only if Shaping is true, that is we are currently writing back a response that matches a certain 83 // url_regex will the other values be set correctly. If so, the Buckets represent the buckets 84 // to be used for the current url_regex. NextActionInfo tells us whether there is an upcoming action 85 // that needs to be performed, and ThrottleContext tells us whether we are currently in a throttle 86 // interval (according to the RangeStart). Note, the ThrottleContext is only used once in the start 87 // to determine the beginning bandwidth. It need not be updated after that. This 88 // is because the subsequent throttles are captured in the upcoming ChangeBandwidth actions. 89 // Byte Offset represents the absolute byte offset of response data that we are currently writing back. 90 // It does not account for the header data. 91 type Context struct { 92 Shaping bool 93 RangeStart int64 94 URLRegex string 95 Buckets *Buckets 96 GlobalBucket *Bucket 97 ThrottleContext *ThrottleContext 98 NextActionInfo *NextActionInfo 99 ByteOffset int64 100 HeaderLen int64 101 HeaderBytesWritten int64 102 } 103 104 // Listener wraps a net.Listener and simulates connection latency and bandwidth 105 // constraints. 106 type Listener struct { 107 net.Listener 108 109 ReadBucket *Bucket 110 WriteBucket *Bucket 111 112 mu sync.RWMutex 113 latency time.Duration 114 GlobalBuckets map[string]*Bucket 115 Shapes *urlShapes 116 defaults *Default 117 } 118 119 // NewListener returns a new bandwidth constrained listener. Defaults to 120 // DefaultBitrate (uncapped). 121 func NewListener(l net.Listener) *Listener { 122 return &Listener{ 123 Listener: l, 124 ReadBucket: NewBucket(DefaultBitrate/8, time.Second), 125 WriteBucket: NewBucket(DefaultBitrate/8, time.Second), 126 Shapes: &urlShapes{M: make(map[string]*urlShape)}, 127 GlobalBuckets: make(map[string]*Bucket), 128 defaults: &Default{ 129 Bandwidth: Bandwidth{ 130 Up: DefaultBitrate / 8, 131 Down: DefaultBitrate / 8, 132 }, 133 Latency: 0, 134 }, 135 } 136 } 137 138 // ReadBitrate returns the bitrate in bits per second for reads. 139 func (l *Listener) ReadBitrate() int64 { 140 return l.ReadBucket.Capacity() * 8 141 } 142 143 // SetReadBitrate sets the bitrate in bits per second for reads. 144 func (l *Listener) SetReadBitrate(bitrate int64) { 145 l.ReadBucket.SetCapacity(bitrate / 8) 146 } 147 148 // WriteBitrate returns the bitrate in bits per second for writes. 149 func (l *Listener) WriteBitrate() int64 { 150 return l.WriteBucket.Capacity() * 8 151 } 152 153 // SetWriteBitrate sets the bitrate in bits per second for writes. 154 func (l *Listener) SetWriteBitrate(bitrate int64) { 155 l.WriteBucket.SetCapacity(bitrate / 8) 156 } 157 158 // SetDefaults sets the default traffic shaping parameters for the listener. 159 func (l *Listener) SetDefaults(defaults *Default) { 160 l.mu.Lock() 161 defer l.mu.Unlock() 162 163 l.defaults = defaults 164 } 165 166 // Defaults returns the default traffic shaping parameters for the listener. 167 func (l *Listener) Defaults() *Default { 168 l.mu.RLock() 169 defer l.mu.RUnlock() 170 171 return l.defaults 172 } 173 174 // Latency returns the latency for connections. 175 func (l *Listener) Latency() time.Duration { 176 l.mu.Lock() 177 defer l.mu.Unlock() 178 179 return l.latency 180 } 181 182 // SetLatency sets the initial latency for connections. 183 func (l *Listener) SetLatency(latency time.Duration) { 184 l.mu.Lock() 185 defer l.mu.Unlock() 186 187 l.latency = latency 188 } 189 190 // GetTrafficShapedConn takes in a normal connection and returns a traffic shaped connection. 191 func (l *Listener) GetTrafficShapedConn(oc net.Conn) *Conn { 192 if tsconn, ok := oc.(*Conn); ok { 193 return tsconn 194 } 195 urlbuckets := make(map[string]*Buckets) 196 globalurlbuckets := make(map[string]*Bucket) 197 198 l.Shapes.RLock() 199 defaults := l.Defaults() 200 latency := l.Latency() 201 defaultBandwidth := defaults.Bandwidth 202 for regex, shape := range l.Shapes.M { 203 // It should be ok to not acquire the read lock on shape, since WriteBucket is never mutated. 204 globalurlbuckets[regex] = shape.Shape.WriteBucket 205 urlbuckets[regex] = NewBuckets(DefaultBitrate/8, shape.Shape.MaxBandwidth) 206 } 207 208 l.Shapes.RUnlock() 209 210 curinfo := &Context{} 211 212 lc := &Conn{ 213 conn: oc, 214 latency: latency, 215 ReadBucket: l.ReadBucket, 216 WriteBucket: l.WriteBucket, 217 Shapes: l.Shapes, 218 GlobalBuckets: globalurlbuckets, 219 LocalBuckets: urlbuckets, 220 Context: curinfo, 221 Established: time.Now(), 222 DefaultBandwidth: defaultBandwidth, 223 Listener: l, 224 } 225 return lc 226 } 227 228 // Accept waits for and returns the next connection to the listener. 229 func (l *Listener) Accept() (net.Conn, error) { 230 oc, err := l.Listener.Accept() 231 if err != nil { 232 log.Errorf("trafficshape: failed accepting connection: %v", err) 233 return nil, err 234 } 235 236 if tconn, ok := oc.(*net.TCPConn); ok { 237 log.Debugf("trafficshape: setting keep-alive for TCP connection") 238 tconn.SetKeepAlive(true) 239 tconn.SetKeepAlivePeriod(3 * time.Minute) 240 } 241 return l.GetTrafficShapedConn(oc), nil 242 } 243 244 // Close closes the read and write buckets along with the underlying listener. 245 func (l *Listener) Close() error { 246 defer log.Debugf("trafficshape: closed read/write buckets and connection") 247 248 l.ReadBucket.Close() 249 l.WriteBucket.Close() 250 251 return l.Listener.Close() 252 }