blob: fc14e10be0ddacb7dcf431212b68d9a1954f4df0 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package discovery
import (
"errors"
"fmt"
"strings"
"unicode/utf8"
"v.io/v23/discovery"
)
const (
maxAdvertisementSize = 512
maxAttachmentSize = 4096
maxNumAttributes = 32
maxNumAttachments = 32
)
// validateKey returns an error if the key is not suitable for advertising.
func validateKey(key string) error {
if len(key) == 0 {
return errors.New("empty key")
}
if strings.HasPrefix(key, "_") {
return errors.New("key starts with '_'")
}
for _, c := range key {
if c < 0x20 || c > 0x7e {
return errors.New("key is not printable US-ASCII")
}
if c == '=' {
return errors.New("key includes '='")
}
}
return nil
}
// validateAttributes returns an error if the attributes are not suitable for advertising.
func validateAttributes(attributes discovery.Attributes) error {
if len(attributes) > maxNumAttributes {
return errors.New("too many")
}
for k, v := range attributes {
if err := validateKey(k); err != nil {
return err
}
if !utf8.ValidString(v) {
return errors.New("value is not valid UTF-8 string")
}
}
return nil
}
// validateAttachments returns an error if the attachments are not suitable for advertising.
func validateAttachments(attachments discovery.Attachments) error {
if len(attachments) > maxNumAttachments {
return errors.New("too many")
}
for k, v := range attachments {
if err := validateKey(k); err != nil {
return err
}
if len(v) > maxAttachmentSize {
return errors.New("too large")
}
}
return nil
}
// sizeOfAd returns the size of ad excluding id and attachments.
func sizeOfAd(ad *discovery.Advertisement) int {
size := len(ad.InterfaceName)
for _, a := range ad.Addresses {
size += len(a)
}
for k, v := range ad.Attributes {
size += len(k) + len(v)
}
return size
}
// validateAd returns an error if ad is not suitable for advertising.
func validateAd(ad *discovery.Advertisement) error {
if !ad.Id.IsValid() {
return errors.New("id not valid")
}
if len(ad.InterfaceName) == 0 {
return errors.New("interface name not provided")
}
if len(ad.Addresses) == 0 {
return errors.New("address not provided")
}
if err := validateAttributes(ad.Attributes); err != nil {
return fmt.Errorf("attributes not valid: %v", err)
}
if err := validateAttachments(ad.Attachments); err != nil {
return fmt.Errorf("attachments not valid: %v", err)
}
if sizeOfAd(ad) > maxAdvertisementSize {
return errors.New("advertisement too large")
}
return nil
}