Exemple #1
0
// send is run in a separate goroutine. It's used
// to ensure clear interleaving of frames and to
// provide assurances of priority and structure.
func (c *Conn) send() {
	// Catch any panics.
	defer func() {
		if v := recover(); v != nil {
			if !c.Closed() {
				log.Printf("Encountered send error: %v (%[1]T)\n", v)
			}
		}
	}()

	// Enter the processing loop.
	i := 1
	for {

		// Once per 5 frames, pick randomly.
		var frame common.Frame
		if i == 0 { // Ignore priority.
			frame = c.selectFrameToSend(false)
		} else { // Normal selection.
			frame = c.selectFrameToSend(true)
		}

		i++
		if i >= 5 {
			i = 0
		}

		if frame == nil {
			c.Close()
			return
		}

		// Compress any name/value header blocks.
		err := frame.Compress(c.compressor)
		if err != nil {
			log.Printf("Error in compression: %v (%T).\n", err, frame)
			return
		}

		debug.Printf("Sending %s:\n", frame.Name())
		debug.Println(frame)

		// Leave the specifics of writing to the
		// connection up to the frame.
		c.refreshWriteTimeout()
		_, err = frame.WriteTo(c.conn)
		if err != nil {
			c.handleReadWriteError(err)
			return
		}
	}
}
Exemple #2
0
// send is run in a separate goroutine. It's used
// to ensure clear interleaving of frames and to
// provide assurances of priority and structure.
func (c *Conn) send() {
	// Catch any panics.
	defer func() {
		if v := recover(); v != nil {
			if !c.Closed() {
				log.Printf("Encountered send error: %v (%[1]T)\n", v)
			}
		}
	}()

	for i := 1; ; i++ {
		if i >= 5 {
			i = 0 // Once per 5 frames, pick randomly.
		}

		var frame common.Frame
		if i == 0 { // Ignore priority.
			frame = c.selectFrameToSend(false)
		} else { // Normal selection.
			frame = c.selectFrameToSend(true)
		}

		if frame == nil {
			c.Close()
			return
		}

		// Process connection-level flow control.
		if c.Subversion > 0 {
			c.connectionWindowLock.Lock()
			if frame, ok := frame.(*frames.DATA); ok {
				size := int64(len(frame.Data))
				constrained := false
				sending := size
				if sending > c.connectionWindowSize {
					sending = c.connectionWindowSize
					constrained = true
				}
				if sending < 0 {
					sending = 0
				}

				c.connectionWindowSize -= sending

				if constrained {
					// Chop off what we can send now.
					partial := new(frames.DATA)
					partial.Flags = frame.Flags
					partial.StreamID = frame.StreamID
					partial.Data = make([]byte, int(sending))
					copy(partial.Data, frame.Data[:sending])
					frame.Data = frame.Data[sending:]

					// Buffer this frame and try again.
					if c.dataBuffer == nil {
						c.dataBuffer = []*frames.DATA{frame}
					} else {
						buffer := make([]*frames.DATA, 1, len(c.dataBuffer)+1)
						buffer[0] = frame
						buffer = append(buffer, c.dataBuffer...)
						c.dataBuffer = buffer
					}

					frame = partial
				}
			}
			c.connectionWindowLock.Unlock()
		}

		// Compress any name/value header blocks.
		err := frame.Compress(c.compressor)
		if err != nil {
			log.Printf("Error in compression: %v (type %T).\n", err, frame)
			c.Close()
			return
		}

		debug.Printf("Sending %s:\n", frame.Name())
		debug.Println(frame)

		// Leave the specifics of writing to the
		// connection up to the frame.
		c.refreshWriteTimeout()
		if _, err = frame.WriteTo(c.conn); err != nil {
			c.handleReadWriteError(err)
			return
		}
	}
}