// handleWindowUpdate performs the processing of WINDOW_UPDATE frames. func (c *Conn) handleWindowUpdate(frame *frames.WINDOW_UPDATE) { sid := frame.StreamID if c.criticalCheck(!sid.Valid(), sid, "Received WINDOW_UPDATE with excessive Stream ID %d", sid) { return } delta := frame.DeltaWindowSize bad := delta > common.MAX_DELTA_WINDOW_SIZE || delta < 1 if c.criticalCheck(bad, sid, "Received WINDOW_UPDATE with invalid delta window size %d", delta) { return } // Handle connection-level flow control. if sid.Zero() && c.Subversion > 0 { c.connectionWindowLock.Lock() defer c.connectionWindowLock.Unlock() if int64(delta)+c.connectionWindowSize > common.MAX_TRANSFER_WINDOW_SIZE { goaway := new(frames.GOAWAY) if c.server != nil { c.lastRequestStreamIDLock.Lock() goaway.LastGoodStreamID = c.lastRequestStreamID c.lastRequestStreamIDLock.Unlock() } else { c.lastPushStreamIDLock.Lock() goaway.LastGoodStreamID = c.lastPushStreamID c.lastPushStreamIDLock.Unlock() } goaway.Status = common.GOAWAY_FLOW_CONTROL_ERROR c.output[0] <- goaway return } c.connectionWindowSize += int64(delta) return } // Check stream is open. c.streamsLock.Lock() stream := c.streams[sid] c.streamsLock.Unlock() if stream == nil || stream.State().ClosedHere() { // This is almost certainly benign return } // Stream ID is fine. stream.ReceiveFrame(frame) }
func (c *Conn) shutdown() { if c.Closed() { return } // Try to inform the other endpoint that the connection is closing. c.sendingLock.Lock() isSending := c.sending != nil c.sendingLock.Unlock() c.goawayLock.Lock() sent := c.goawaySent c.goawayReceived = true c.goawayLock.Unlock() if !sent && !isSending { goaway := new(frames.GOAWAY) if c.server != nil { c.lastRequestStreamIDLock.Lock() goaway.LastGoodStreamID = c.lastRequestStreamID c.lastRequestStreamIDLock.Unlock() } else { c.lastPushStreamIDLock.Lock() goaway.LastGoodStreamID = c.lastPushStreamID c.lastPushStreamIDLock.Unlock() } select { case c.output[0] <- goaway: c.goawayLock.Lock() c.goawaySent = true c.goawayLock.Unlock() case <-time.After(100 * time.Millisecond): debug.Println("Failed to send closing GOAWAY.") } } // Close all streams. Make a copy so close() can modify the map. var streams []common.Stream c.streamsLock.Lock() for key, stream := range c.streams { streams = append(streams, stream) delete(c.streams, key) } c.streamsLock.Unlock() for _, stream := range streams { stream.Close() } // Ensure any pending frames are sent. c.sendingLock.Lock() if c.sending == nil { c.sending = make(chan struct{}) c.sendingLock.Unlock() select { case <-c.sending: case <-time.After(200 * time.Millisecond): } c.sendingLock.Lock() } c.sending = nil c.sendingLock.Unlock() select { case _, ok := <-c.stop: if ok { close(c.stop) } default: close(c.stop) } c.connLock.Lock() if c.conn != nil { c.conn.Close() c.conn = nil } c.connLock.Unlock() if compressor := c.compressor; compressor != nil { compressor.Close() } c.pushedResources = nil for _, stream := range c.output { select { case _, ok := <-stream: if ok { close(stream) } default: close(stream) } } }
func (c *Conn) _GOAWAY(status common.StatusCode) { goaway := new(frames.GOAWAY) goaway.Status = status c.output[0] <- goaway c.Close() }