common.go raw

   1  package wire
   2  
   3  import (
   4  	"crypto/rand"
   5  	"encoding/binary"
   6  	"fmt"
   7  	"io"
   8  	"math"
   9  	"time"
  10  	
  11  	"github.com/p9c/p9/pkg/chainhash"
  12  )
  13  
  14  const (
  15  	// MaxVarIntPayload is the maximum payload size for a variable length integer.
  16  	MaxVarIntPayload = 9
  17  	// binaryFreeListMaxItems is the number of buffers to keep in the free list to
  18  	// use for binary serialization and deserialization.
  19  	binaryFreeListMaxItems = 16384
  20  )
  21  
  22  var (
  23  	// littleEndian is a convenience variable since binary.LittleEndian is quite
  24  	// long.
  25  	littleEndian = binary.LittleEndian
  26  	// bigEndian is a convenience variable since binary.BigEndian is quite long.
  27  	bigEndian = binary.BigEndian
  28  )
  29  
  30  // binaryFreeList defines a concurrent safe free list of byte slices (up to the
  31  // maximum number defined by the binaryFreeListMaxItems constant) that have a
  32  // cap of 8 (thus it supports up to a uint64). It is used to provide temporary
  33  // buffers for deserializing primitive numbers to and from their binary encoding
  34  // in order to greatly reduce the number of allocations required. For
  35  // convenience, functions are provided for each of the primitive unsigned
  36  // integers that automatically obtain a buffer from the free list, perform the
  37  // necessary binary conversion, read from or write to the given io.Reader or
  38  // io.Writer, and return the buffer to the free list.
  39  type binaryFreeList chan []byte
  40  
  41  // Borrow returns a byte slice from the free list with a length of 8.  A new buffer is allocated if there are not any available on the free list.
  42  func (l binaryFreeList) Borrow() []byte {
  43  	var buf []byte
  44  	select {
  45  	case buf = <-l:
  46  	default:
  47  		buf = make([]byte, 8)
  48  	}
  49  	return buf[:8]
  50  }
  51  
  52  // Return puts the provided byte slice back on the free list. The buffer MUST have been obtained via the Borrow function
  53  // and therefore have a cap of 8.
  54  func (l binaryFreeList) Return(buf []byte) {
  55  	select {
  56  	case l <- buf:
  57  	default:
  58  		// Let it go to the garbage collector.
  59  	}
  60  }
  61  
  62  // Uint8 reads a single byte from the provided reader using a buffer from the free list and returns it as a uint8.
  63  func (l binaryFreeList) Uint8(r io.Reader) (rv uint8, e error) {
  64  	buf := l.Borrow()[:1]
  65  	if _, e = io.ReadFull(r, buf); E.Chk(e) {
  66  		l.Return(buf)
  67  		return 0, e
  68  	}
  69  	rv = buf[0]
  70  	l.Return(buf)
  71  	return rv, nil
  72  }
  73  
  74  // Uint16 reads two bytes from the provided reader using a buffer from the free
  75  // list, converts it to a number using the provided byte order, and returns the
  76  // resulting uint16.
  77  func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (rv uint16, e error) {
  78  	buf := l.Borrow()[:2]
  79  	if _, e = io.ReadFull(r, buf); E.Chk(e) {
  80  		l.Return(buf)
  81  		return
  82  	}
  83  	rv = byteOrder.Uint16(buf)
  84  	l.Return(buf)
  85  	return rv, nil
  86  }
  87  
  88  // Uint32 reads four bytes from the provided reader using a buffer from the free
  89  // list, converts it to a number using the provided byte order, and returns the
  90  // resulting uint32.
  91  func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (rv uint32, e error) {
  92  	buf := l.Borrow()[:4]
  93  	if _, e = io.ReadFull(r, buf); E.Chk(e) {
  94  		l.Return(buf)
  95  		return 0, e
  96  	}
  97  	rv = byteOrder.Uint32(buf)
  98  	l.Return(buf)
  99  	return rv, nil
 100  }
 101  
 102  // Uint64 reads eight bytes from the provided reader using a buffer from the
 103  // free list, converts it to a number using the provided byte order, and returns
 104  // the resulting uint64.
 105  func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (rv uint64, e error) {
 106  	buf := l.Borrow()[:8]
 107  	if _, e = io.ReadFull(r, buf); E.Chk(e) {
 108  		l.Return(buf)
 109  		return
 110  	}
 111  	rv = byteOrder.Uint64(buf)
 112  	l.Return(buf)
 113  	return rv, nil
 114  }
 115  
 116  // PutUint8 copies the provided uint8 into a buffer from the free list and writes the resulting byte to the given
 117  // writer.
 118  func (l binaryFreeList) PutUint8(w io.Writer, val uint8) (e error) {
 119  	buf := l.Borrow()[:1]
 120  	buf[0] = val
 121  	_, e = w.Write(buf)
 122  	l.Return(buf)
 123  	return e
 124  }
 125  
 126  // PutUint16 serializes the provided uint16 using the given byte order into a buffer from the free list and writes the
 127  // resulting two bytes to the given writer.
 128  func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) (e error) {
 129  	buf := l.Borrow()[:2]
 130  	byteOrder.PutUint16(buf, val)
 131  	_, e = w.Write(buf)
 132  	l.Return(buf)
 133  	return
 134  }
 135  
 136  // PutUint32 serializes the provided uint32 using the given byte order into a buffer from the free list and writes the
 137  // resulting four bytes to the given writer.
 138  func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) (e error) {
 139  	buf := l.Borrow()[:4]
 140  	byteOrder.PutUint32(buf, val)
 141  	_, e = w.Write(buf)
 142  	l.Return(buf)
 143  	return
 144  }
 145  
 146  // PutUint64 serializes the provided uint64 using the given byte order into a buffer from the free list and writes the
 147  // resulting eight bytes to the given writer.
 148  func (l binaryFreeList) PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) (e error) {
 149  	buf := l.Borrow()[:8]
 150  	byteOrder.PutUint64(buf, val)
 151  	_, e = w.Write(buf)
 152  	l.Return(buf)
 153  	return
 154  }
 155  
 156  // binarySerializer provides a free list of buffers to use for serializing and deserializing primitive integer values to
 157  // and from io.Readers and io.Writers.
 158  var binarySerializer binaryFreeList = make(chan []byte, binaryFreeListMaxItems)
 159  
 160  // errNonCanonicalVarInt is the common format string used for non-canonically encoded variable length integer errors.
 161  var errNonCanonicalVarInt = "non-canonical varint %x - discriminant %x must " +
 162  	"encode a value greater than %x"
 163  
 164  // uint32Time represents a unix timestamp encoded with a uint32. It is used as a way to signal the readElement function
 165  // how to decode a timestamp into a Go time.Time since it is otherwise ambiguous.
 166  type uint32Time time.Time
 167  
 168  // int64Time represents a unix timestamp encoded with an int64. It is used as a way to signal the readElement function
 169  // how to decode a timestamp into a Go time.Time since it is otherwise ambiguous.
 170  type int64Time time.Time
 171  
 172  // readElement reads the next sequence of bytes from r using little endian depending on the concrete type of element
 173  // pointed to.
 174  func readElement(r io.Reader, element interface{}) (e error) {
 175  	// Attempt to read the element based on the concrete type via fast type assertions first.
 176  	switch l := element.(type) {
 177  	case *int32:
 178  		var rv uint32
 179  		if rv, e = binarySerializer.Uint32(r, littleEndian); E.Chk(e) {
 180  			return
 181  		}
 182  		*l = int32(rv)
 183  		return
 184  	case *uint32:
 185  		var rv uint32
 186  		if rv, e = binarySerializer.Uint32(r, littleEndian); E.Chk(e) {
 187  			return
 188  		}
 189  		*l = rv
 190  		return
 191  	case *int64:
 192  		var rv uint64
 193  		if rv, e = binarySerializer.Uint64(r, littleEndian); E.Chk(e) {
 194  			return
 195  		}
 196  		*l = int64(rv)
 197  		return
 198  	case *uint64:
 199  		var rv uint64
 200  		if rv, e = binarySerializer.Uint64(r, littleEndian); E.Chk(e) {
 201  			return
 202  		}
 203  		*l = rv
 204  		return
 205  	case *bool:
 206  		var rv uint8
 207  		if rv, e = binarySerializer.Uint8(r); E.Chk(e) {
 208  			return
 209  		}
 210  		if rv == 0x00 {
 211  			*l = false
 212  		} else {
 213  			*l = true
 214  		}
 215  		return nil
 216  	// Unix timestamp encoded as a uint32.
 217  	case *uint32Time:
 218  		var rv uint32
 219  		if rv, e = binarySerializer.Uint32(r, binary.LittleEndian); E.Chk(e) {
 220  			return
 221  		}
 222  		*l = uint32Time(time.Unix(int64(rv), 0))
 223  		return
 224  	// Unix timestamp encoded as an int64.
 225  	case *int64Time:
 226  		var rv uint64
 227  		if rv, e = binarySerializer.Uint64(r, binary.LittleEndian); E.Chk(e) {
 228  			return
 229  		}
 230  		*l = int64Time(time.Unix(int64(rv), 0))
 231  		return
 232  	// Message header checksum.
 233  	case *[4]byte:
 234  		if _, e = io.ReadFull(r, l[:]); E.Chk(e) {
 235  		}
 236  		return
 237  	// Message header command.
 238  	case *[CommandSize]uint8:
 239  		if _, e = io.ReadFull(r, l[:]); E.Chk(e) {
 240  		}
 241  		return
 242  	// IP address.
 243  	case *[16]byte:
 244  		if _, e = io.ReadFull(r, l[:]); E.Chk(e) {
 245  		}
 246  		return
 247  	case *chainhash.Hash:
 248  		if _, e = io.ReadFull(r, l[:]); E.Chk(e) {
 249  			return
 250  		}
 251  		return nil
 252  	case *ServiceFlag:
 253  		var rv uint64
 254  		if rv, e = binarySerializer.Uint64(r, littleEndian); E.Chk(e) {
 255  			return
 256  		}
 257  		*l = ServiceFlag(rv)
 258  		return
 259  	case *InvType:
 260  		var rv uint32
 261  		if rv, e = binarySerializer.Uint32(r, littleEndian); E.Chk(e) {
 262  			return
 263  		}
 264  		*l = InvType(rv)
 265  		return
 266  	case *BitcoinNet:
 267  		var rv uint32
 268  		if rv, e = binarySerializer.Uint32(r, littleEndian); E.Chk(e) {
 269  			return
 270  		}
 271  		*l = BitcoinNet(rv)
 272  		return
 273  	case *BloomUpdateType:
 274  		var rv uint8
 275  		if rv, e = binarySerializer.Uint8(r); E.Chk(e) {
 276  			return
 277  		}
 278  		*l = BloomUpdateType(rv)
 279  		return
 280  	case *RejectCode:
 281  		var rv uint8
 282  		if rv, e = binarySerializer.Uint8(r); E.Chk(e) {
 283  			return
 284  		}
 285  		*l = RejectCode(rv)
 286  		return
 287  	}
 288  	// Fall back to the slower binary.Read if a fast path was not available above.
 289  	return binary.Read(r, littleEndian, element)
 290  }
 291  
 292  // readElements reads multiple items from r.  It is equivalent to multiple calls to readElement.
 293  func readElements(r io.Reader, elements ...interface{}) (e error) {
 294  	for _, element := range elements {
 295  		if e = readElement(r, element); E.Chk(e) {
 296  			return
 297  		}
 298  	}
 299  	return
 300  }
 301  
 302  // writeElement writes the little endian representation of element to w.
 303  func writeElement(w io.Writer, element interface{}) (e error) {
 304  	// Attempt to write the element based on the concrete type via fast type assertions first.
 305  	switch el := element.(type) {
 306  	case int32:
 307  		if e = binarySerializer.PutUint32(w, littleEndian, uint32(el)); E.Chk(e) {
 308  			return
 309  		}
 310  		return
 311  	case uint32:
 312  		if e = binarySerializer.PutUint32(w, littleEndian, el); E.Chk(e) {
 313  		}
 314  		return
 315  	case int64:
 316  		if e = binarySerializer.PutUint64(w, littleEndian, uint64(el)); E.Chk(e) {
 317  		}
 318  		return
 319  	case uint64:
 320  		if e = binarySerializer.PutUint64(w, littleEndian, el); E.Chk(e) {
 321  		}
 322  		return
 323  	case bool:
 324  		if el {
 325  			e = binarySerializer.PutUint8(w, 0x01)
 326  		} else {
 327  			e = binarySerializer.PutUint8(w, 0x00)
 328  		}
 329  		if E.Chk(e) {
 330  			return
 331  		}
 332  		return nil
 333  	// Message header checksum.
 334  	case [4]byte:
 335  		if _, e = w.Write(el[:]); E.Chk(e) {
 336  			return
 337  		}
 338  		return
 339  	// Message header command.
 340  	case [CommandSize]uint8:
 341  		if _, e = w.Write(el[:]); E.Chk(e) {
 342  		}
 343  		return
 344  	// IP address.
 345  	case [16]byte:
 346  		if _, e = w.Write(el[:]); E.Chk(e) {
 347  		}
 348  		return
 349  	case *chainhash.Hash:
 350  		if _, e = w.Write(el[:]); E.Chk(e) {
 351  		}
 352  		return
 353  	case ServiceFlag:
 354  		if e = binarySerializer.PutUint64(w, littleEndian, uint64(el)); E.Chk(e) {
 355  		}
 356  		return
 357  	case InvType:
 358  		if e = binarySerializer.PutUint32(w, littleEndian, uint32(el)); E.Chk(e) {
 359  		}
 360  		return
 361  	case BitcoinNet:
 362  		if e = binarySerializer.PutUint32(w, littleEndian, uint32(el)); E.Chk(e) {
 363  		}
 364  		return
 365  	case BloomUpdateType:
 366  		if e = binarySerializer.PutUint8(w, uint8(el)); E.Chk(e) {
 367  		}
 368  		return
 369  	case RejectCode:
 370  		if e = binarySerializer.PutUint8(w, uint8(el)); E.Chk(e) {
 371  			return
 372  		}
 373  		return
 374  	}
 375  	// Fall back to the slower binary.Write if a fast path was not available above.
 376  	return binary.Write(w, littleEndian, element)
 377  }
 378  
 379  // writeElements writes multiple items to w.  It is equivalent to multiple calls to writeElement.
 380  func writeElements(w io.Writer, elements ...interface{}) (e error) {
 381  	for _, element := range elements {
 382  		if e = writeElement(w, element); E.Chk(e) {
 383  			return
 384  		}
 385  	}
 386  	return
 387  }
 388  
 389  // ReadVarInt reads a variable length integer from r and returns it as a uint64.
 390  func ReadVarInt(r io.Reader, pver uint32) (rv uint64, e error) {
 391  	var discriminant uint8
 392  	if discriminant, e = binarySerializer.Uint8(r); E.Chk(e) {
 393  		return
 394  	}
 395  	switch discriminant {
 396  	case 0xff:
 397  		var sv uint64
 398  		if sv, e = binarySerializer.Uint64(r, littleEndian); E.Chk(e) {
 399  			return
 400  		}
 401  		rv = sv
 402  		// The encoding is not canonical if the value could have been encoded using fewer bytes.
 403  		min := uint64(0x100000000)
 404  		if rv < min {
 405  			return 0, messageError(
 406  				"ReadVarInt", fmt.Sprintf(
 407  					errNonCanonicalVarInt, rv, discriminant, min,
 408  				),
 409  			)
 410  		}
 411  	case 0xfe:
 412  		var sv uint32
 413  		if sv, e = binarySerializer.Uint32(r, littleEndian); E.Chk(e) {
 414  			return
 415  		}
 416  		rv = uint64(sv)
 417  		// The encoding is not canonical if the value could have been encoded using fewer bytes.
 418  		min := uint64(0x10000)
 419  		if rv < min {
 420  			return 0, messageError(
 421  				"ReadVarInt", fmt.Sprintf(
 422  					errNonCanonicalVarInt, rv, discriminant, min,
 423  				),
 424  			)
 425  		}
 426  	case 0xfd:
 427  		var sv uint16
 428  		if sv, e = binarySerializer.Uint16(r, littleEndian); E.Chk(e) {
 429  			return
 430  		}
 431  		rv = uint64(sv)
 432  		// The encoding is not canonical if the value could have been encoded using fewer bytes.
 433  		min := uint64(0xfd)
 434  		if rv < min {
 435  			return 0, messageError(
 436  				"ReadVarInt", fmt.Sprintf(
 437  					errNonCanonicalVarInt, rv, discriminant, min,
 438  				),
 439  			)
 440  		}
 441  	default:
 442  		rv = uint64(discriminant)
 443  	}
 444  	return
 445  }
 446  
 447  // WriteVarInt serializes val to w using a variable number of bytes depending on its value.
 448  func WriteVarInt(w io.Writer, pver uint32, val uint64) (e error) {
 449  	if val < 0xfd {
 450  		return binarySerializer.PutUint8(w, uint8(val))
 451  	}
 452  	if val <= math.MaxUint16 {
 453  		if e = binarySerializer.PutUint8(w, 0xfd); E.Chk(e) {
 454  			return
 455  		}
 456  		return binarySerializer.PutUint16(w, littleEndian, uint16(val))
 457  	}
 458  	if val <= math.MaxUint32 {
 459  		if e = binarySerializer.PutUint8(w, 0xfe); E.Chk(e) {
 460  			return
 461  		}
 462  		return binarySerializer.PutUint32(w, littleEndian, uint32(val))
 463  	}
 464  	if e = binarySerializer.PutUint8(w, 0xff); E.Chk(e) {
 465  		return
 466  	}
 467  	return binarySerializer.PutUint64(w, littleEndian, val)
 468  }
 469  
 470  // VarIntSerializeSize returns the number of bytes it would take to serialize val as a variable length integer.
 471  func VarIntSerializeSize(val uint64) int {
 472  	// The value is small enough to be represented by itself, so it's just 1 byte.
 473  	if val < 0xfd {
 474  		return 1
 475  	}
 476  	// Discriminant 1 byte plus 2 bytes for the uint16.
 477  	if val <= math.MaxUint16 {
 478  		return 3
 479  	}
 480  	// Discriminant 1 byte plus 4 bytes for the uint32.
 481  	if val <= math.MaxUint32 {
 482  		return 5
 483  	}
 484  	// Discriminant 1 byte plus 8 bytes for the uint64.
 485  	return 9
 486  }
 487  
 488  // ReadVarString reads a variable length string from r and returns it as a Go string. A variable length string is
 489  // encoded as a variable length integer containing the length of the string followed by the bytes that represent the
 490  // string itself. An error is returned if the length is greater than the maximum block payload size since it helps
 491  // protect against memory exhaustion attacks and forced panics through malformed messages.
 492  func ReadVarString(r io.Reader, pver uint32) (s string, e error) {
 493  	var count uint64
 494  	if count, e = ReadVarInt(r, pver); E.Chk(e) {
 495  		return
 496  	}
 497  	// Prevent variable length strings that are larger than the maximum message size. It would be possible to cause
 498  	// memory exhaustion and panics without a sane upper bound on this count.
 499  	if count > MaxMessagePayload {
 500  		str := fmt.Sprintf(
 501  			"variable length string is too long "+
 502  				"[count %d, max %d]", count, MaxMessagePayload,
 503  		)
 504  		return "", messageError("ReadVarString", str)
 505  	}
 506  	buf := make([]byte, count)
 507  	if _, e = io.ReadFull(r, buf); E.Chk(e) {
 508  		return
 509  	}
 510  	return string(buf), e
 511  }
 512  
 513  // WriteVarString serializes str to w as a variable length integer containing the length of the string followed by the
 514  // bytes that represent the string itself.
 515  func WriteVarString(w io.Writer, pver uint32, str string) (e error) {
 516  	if e = WriteVarInt(w, pver, uint64(len(str))); E.Chk(e) {
 517  		return
 518  	}
 519  	_, e = w.Write([]byte(str))
 520  	return
 521  }
 522  
 523  // ReadVarBytes reads a variable length byte array. A byte array is encoded as a varInt containing the length of the
 524  // array followed by the bytes themselves. An error is returned if the length is greater than the passed maxAllowed
 525  // parameter which helps protect against memory exhaustion attacks and forced panics through malformed messages. The
 526  // fieldName parameter is only used for the error message so it provides more context in the error.
 527  func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32, fieldName string) (b []byte, e error) {
 528  	var count uint64
 529  	if count, e = ReadVarInt(r, pver); E.Chk(e) {
 530  		return
 531  	}
 532  	// Prevent byte array larger than the max message size. It would be possible to cause memory exhaustion and panics
 533  	// without a sane upper bound on this count.
 534  	if count > uint64(maxAllowed) {
 535  		str := fmt.Sprintf(
 536  			"%s is larger than the max allowed size "+
 537  				"[count %d, max %d]", fieldName, count, maxAllowed,
 538  		)
 539  		e = messageError("ReadVarBytes", str)
 540  		return
 541  	}
 542  	b = make([]byte, count)
 543  	if _, e = io.ReadFull(r, b); E.Chk(e) {
 544  	}
 545  	return
 546  }
 547  
 548  // WriteVarBytes serializes a variable length byte array to w as a varInt containing the number of bytes, followed by
 549  // the bytes themselves.
 550  func WriteVarBytes(w io.Writer, pver uint32, bytes []byte) (e error) {
 551  	slen := uint64(len(bytes))
 552  	if e = WriteVarInt(w, pver, slen); E.Chk(e) {
 553  		return
 554  	}
 555  	_, e = w.Write(bytes)
 556  	return
 557  }
 558  
 559  // randomUint64 returns a cryptographically random uint64 value. This unexported version takes a reader primarily to
 560  // ensure the error paths can be properly tested by passing a fake reader in the tests.
 561  func randomUint64(r io.Reader) (rv uint64, e error) {
 562  	if rv, e = binarySerializer.Uint64(r, bigEndian); E.Chk(e) {
 563  	}
 564  	return
 565  }
 566  
 567  // RandomUint64 returns a cryptographically random uint64 value.
 568  func RandomUint64() (rv uint64, e error) {
 569  	return randomUint64(rand.Reader)
 570  }
 571