예제 #1
0
파일: processing.go 프로젝트: vonwenm/spdy
// 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)
}
예제 #2
0
파일: shutdown.go 프로젝트: vonwenm/spdy
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)
		}
	}
}
예제 #3
0
func (c *Conn) _GOAWAY(status common.StatusCode) {
	goaway := new(frames.GOAWAY)
	goaway.Status = status
	c.output[0] <- goaway
	c.Close()
}