code: func (p *PortAllocator) RequestPortInRange(ip net.IP, proto string, portStart, portEnd int) (int, error) {
  	p.mutex.Lock()
  	defer p.mutex.Unlock()
  
  	if proto != "tcp" && proto != "udp" && proto != "sctp" {
  		return 0, ErrUnknownProtocol
  	}
  
  	if ip == nil {
  		ip = defaultIP
  	}
  	ipstr := ip.String()
  	protomap, ok := p.ipMap[ipstr]
  	if !ok {
  		protomap = protoMap{
  			"tcp":  p.newPortMap(),
  			"udp":  p.newPortMap(),
  			"sctp": p.newPortMap(),
  		}
  
  		p.ipMap[ipstr] = protomap
  	}
  	mapping := protomap[proto]
  	if portStart > 0 && portStart == portEnd {
  		if _, ok := mapping.p[portStart]; !ok {
  			mapping.p[portStart] = struct{}{}
  			return portStart, nil
  		}
  		return 0, newErrPortAlreadyAllocated(ipstr, portStart)
  	}
  
  	port, err := mapping.findPort(portStart, portEnd)
  	if err != nil {
  		return 0, err
  	}
  	return port, nil
  }
docs: // RequestPortInRange requests new port from global ports pool for specified ip and proto.
  // If portStart and portEnd are 0 it returns the first free port in the default ephemeral range.
  // If portStart != portEnd it returns the first free port in the requested range.
  // Otherwise (portStart == portEnd) it checks port availability in the requested proto's port-pool
  // and returns that port or error if port is already busy.