func()

in vncclient/server_messages.go [46:128]


func (*FramebufferUpdateMessage) Read(c *ClientConn, r io.Reader) (ServerMessage, error) {
	start := time.Now().UnixNano()

	// Read off the padding
	var padding [1]byte
	if _, err := io.ReadFull(r, padding[:]); err != nil {
		return nil, err
	}

	var numRects uint16
	if err := binary.Read(r, binary.BigEndian, &numRects); err != nil {
		return nil, err
	}
    if numRects > 1000 {
        return nil, errors.Errorf("excessive rectangle count %d", int(numRects));
    }

	// Build the map of encodings supported
	encMap := make(map[int32]Encoding)
	for _, enc := range c.Encs {
		encMap[enc.Type()] = enc
	}

	// We must always support the raw encoding
	rawEnc := new(RawEncoding)
	encMap[rawEnc.Type()] = rawEnc

	// Let's also support ZRLEEnocding
	// zrleEnc := new(ZRLEEncoding)
	// encMap[zrleEnc.Type()] = zrleEnc

	rects := make([]Rectangle, numRects)
	for i := uint16(0); i < numRects; i++ {
		var encodingType int32

		rect := &rects[i]
		data := []interface{}{
			&rect.X,
			&rect.Y,
			&rect.Width,
			&rect.Height,
			&encodingType,
		}

		for _, val := range data {
			if err := binary.Read(r, binary.BigEndian, val); err != nil {
				return nil, err
			}
		}

        // Defend against corrupt rectangles before we try to allocate memory.
        // In the encoding readers we compute int(Width) * int(Height), which will overflow if Width*Height >= (1<<31)
        if int(rect.X) > 5120 || int(rect.Y) > 2880 || int(rect.Width) > 5120 || int(rect.Height) > 2880 {
            return nil, errors.Errorf("excessive rectangle origin %dx%d size %dx%d encoding %v", int(rect.X), int(rect.Y), int(rect.Width), int(rect.Height), encodingType);
        }

		enc, ok := encMap[encodingType]
		if !ok {
			return nil, errors.Errorf("unsupported encoding type: %v", encodingType)
		}

		var err error
		rect.Enc, err = enc.Read(c, rect, r)
		if err != nil {
			return nil, err
		}
	}

	var bytes int
	types := map[string]int{}
	for _, rect := range rects {
		bytes += rect.Enc.Size()
		t := reflect.TypeOf(rect.Enc).String()
		types[t]++
	}

	delta := (time.Now().UnixNano() - start) / 1000 / 1000
	if delta > 1 {
		// log.Infof("Time to parse framebuffer update message: %vms (bytes: %v, rects: %v)", delta, bytes, types)
	}

	return &FramebufferUpdateMessage{rects}, nil
}