/*
 * Comparison function for the subnet inclusion/overlap operators
 *
 * If the comparison is okay for the specified inclusion operator, the return
 * value will be 0.  Otherwise the return value will be less than or greater
 * than 0 as appropriate for the operator.
 *
 * Comparison is compatible with the basic comparison function for the inet
 * type.  See network_cmp_internal() in network.c for the original.  Basic
 * comparison operators are implemented with the network_cmp_internal()
 * function.  It is possible to implement the subnet inclusion operators with
 * this function.
 *
 * Comparison is first on the common bits of the network part, then on the
 * length of the network part (masklen) as in the network_cmp_internal()
 * function.  Only the first part is in this function.  The second part is
 * separated to another function for reusability.  The difference between the
 * second part and the original network_cmp_internal() is that the inclusion
 * operator is considered while comparing the lengths of the network parts.
 * See the inet_masklen_inclusion_cmp() function below.
 */
static int
inet_inclusion_cmp(inet *left, inet *right, int opr_codenum)
{
	if (ip_family(left) == ip_family(right))
	{
		int			order;

		order = bitncmp(ip_addr(left), ip_addr(right),
						Min(ip_bits(left), ip_bits(right)));
		if (order != 0)
			return order;

		return inet_masklen_inclusion_cmp(left, right, opr_codenum);
	}

	return ip_family(left) - ip_family(right);
}
Exemplo n.º 2
0
int chk_who(aClient *ac, int showall)
{
    if(!IsClient(ac))
	return 0;
    if(IsInvisible(ac) && !showall)
	return 0;

    if(wsopts.client_type_plus &&
	wsopts.client_type != ac->user->servicetype)
	return 0;

    if(wsopts.check_umode)
	if((wsopts.umode_plus && 
	    !((ac->umode&wsopts.umodes)==wsopts.umodes)) ||
	   (!wsopts.umode_plus && ((ac->umode&wsopts.umodes)==wsopts.umodes)))
	    return 0;

    if(wsopts.check_away)
	if((wsopts.away_plus && ac->user->away==NULL) ||
	   (!wsopts.away_plus && ac->user->away!=NULL))
	    return 0;

    /* while this is wasteful now, in the future
     * when clients contain pointers to their servers
     * of origin, this'll become a 4 byte check instead of a mycmp
     * -wd */
    /* welcome to the future... :) - lucas */
    if(wsopts.serv_plus)
    {
	if(wsopts.server != ac->uplink)
	    return 0;
	/* don't let people find hidden opers via /who +s server */
	if(IsUmodeI(ac) && !showall)
	    return 0;
    }
    /* we only call match once, since if the first condition
     * isn't true, most (all?) compilers will never try the
     * second...phew :) */
    if(wsopts.user!=NULL)
	if((wsopts.user_plus && uchkfn(wsopts.user, ac->user->username)) ||
	   (!wsopts.user_plus && !uchkfn(wsopts.user, ac->user->username)))
	    return 0;

    if(wsopts.nick!=NULL)
	if((wsopts.nick_plus && nchkfn(wsopts.nick, ac->name)) ||
	   (!wsopts.nick_plus && !nchkfn(wsopts.nick, ac->name)))
	    return 0;
    
    if(wsopts.host!=NULL)
	if((wsopts.host_plus && hchkfn(wsopts.host, ac->user->host)) ||
	   (!wsopts.host_plus && !hchkfn(wsopts.host, ac->user->host)))
	    return 0;

    if(wsopts.cidr_plus)
	if(ac->ip_family != wsopts.cidr_family ||
	   bitncmp(&ac->ip, &wsopts.cidr_ip, wsopts.cidr_bits) != 0)
	    return 0;
    
    if(wsopts.ip_plus)
	if(ichkfn(wsopts.ip, ac->hostip))
	    return 0;
    
    if(wsopts.gcos!=NULL)
	if((wsopts.gcos_plus && gchkfn(wsopts.gcos, ac->info)) ||
	   (!wsopts.gcos_plus && !gchkfn(wsopts.gcos, ac->info)))
	    return 0;

    /*
     * For the below options, a value of two means '+', 
     * a value of 1 means '-', and a value of 0 means
     * not speficied. 
     */

    if(wsopts.ts_value == 2 && /* +t */
        NOW - ac->tsinfo < wsopts.ts)
        return 0;
    else if(wsopts.ts_value == 1 && /* -t */
        NOW - ac->tsinfo >= wsopts.ts)
        return 0;

    return 1;
}
Exemplo n.º 3
0
/*
 * The SP-GiST choose function
 */
Datum
inet_spg_choose(PG_FUNCTION_ARGS)
{
	spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
	spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
	inet	   *val = DatumGetInetPP(in->datum),
			   *prefix;
	int			commonbits;

	/*
	 * If we're looking at a tuple that splits by address family, choose the
	 * appropriate subnode.
	 */
	if (!in->hasPrefix)
	{
		/* allTheSame isn't possible for such a tuple */
		Assert(!in->allTheSame);
		Assert(in->nNodes == 2);

		out->resultType = spgMatchNode;
		out->result.matchNode.nodeN = (ip_family(val) == PGSQL_AF_INET) ? 0 : 1;
		out->result.matchNode.restDatum = InetPGetDatum(val);

		PG_RETURN_VOID();
	}

	/* Else it must split by prefix */
	Assert(in->nNodes == 4 || in->allTheSame);

	prefix = DatumGetInetPP(in->prefixDatum);
	commonbits = ip_bits(prefix);

	/*
	 * We cannot put addresses from different families under the same inner
	 * node, so we have to split if the new value's family is different.
	 */
	if (ip_family(val) != ip_family(prefix))
	{
		/* Set up 2-node tuple */
		out->resultType = spgSplitTuple;
		out->result.splitTuple.prefixHasPrefix = false;
		out->result.splitTuple.prefixNNodes = 2;
		out->result.splitTuple.prefixNodeLabels = NULL;

		/* Identify which node the existing data goes into */
		out->result.splitTuple.childNodeN =
			(ip_family(prefix) == PGSQL_AF_INET) ? 0 : 1;

		out->result.splitTuple.postfixHasPrefix = true;
		out->result.splitTuple.postfixPrefixDatum = InetPGetDatum(prefix);

		PG_RETURN_VOID();
	}

	/*
	 * If the new value does not match the existing prefix, we have to split.
	 */
	if (ip_bits(val) < commonbits ||
		bitncmp(ip_addr(prefix), ip_addr(val), commonbits) != 0)
	{
		/* Determine new prefix length for the split tuple */
		commonbits = bitncommon(ip_addr(prefix), ip_addr(val),
								Min(ip_bits(val), commonbits));

		/* Set up 4-node tuple */
		out->resultType = spgSplitTuple;
		out->result.splitTuple.prefixHasPrefix = true;
		out->result.splitTuple.prefixPrefixDatum =
			InetPGetDatum(cidr_set_masklen_internal(val, commonbits));
		out->result.splitTuple.prefixNNodes = 4;
		out->result.splitTuple.prefixNodeLabels = NULL;

		/* Identify which node the existing data goes into */
		out->result.splitTuple.childNodeN =
			inet_spg_node_number(prefix, commonbits);

		out->result.splitTuple.postfixHasPrefix = true;
		out->result.splitTuple.postfixPrefixDatum = InetPGetDatum(prefix);

		PG_RETURN_VOID();
	}

	/*
	 * All OK, choose the node to descend into.  (If this tuple is marked
	 * allTheSame, the core code will ignore our choice of nodeN; but we need
	 * not account for that case explicitly here.)
	 */
	out->resultType = spgMatchNode;
	out->result.matchNode.nodeN = inet_spg_node_number(val, commonbits);
	out->result.matchNode.restDatum = InetPGetDatum(val);

	PG_RETURN_VOID();
}
Exemplo n.º 4
0
/*
 * Calculate bitmap of node numbers that are consistent with the query
 *
 * This can be used either at a 4-way inner tuple, or at a leaf tuple.
 * In the latter case, we should return a boolean result (0 or 1)
 * not a bitmap.
 *
 * This definition is pretty odd, but the inner and leaf consistency checks
 * are mostly common and it seems best to keep them in one function.
 */
static int
inet_spg_consistent_bitmap(const inet *prefix, int nkeys, ScanKey scankeys,
						   bool leaf)
{
	int			bitmap;
	int			commonbits,
				i;

	/* Initialize result to allow visiting all children */
	if (leaf)
		bitmap = 1;
	else
		bitmap = 1 | (1 << 1) | (1 << 2) | (1 << 3);

	commonbits = ip_bits(prefix);

	for (i = 0; i < nkeys; i++)
	{
		inet	   *argument = DatumGetInetPP(scankeys[i].sk_argument);
		StrategyNumber strategy = scankeys[i].sk_strategy;
		int			order;

		/*
		 * Check 0: different families
		 *
		 * Matching families do not help any of the strategies.
		 */
		if (ip_family(argument) != ip_family(prefix))
		{
			switch (strategy)
			{
				case RTLessStrategyNumber:
				case RTLessEqualStrategyNumber:
					if (ip_family(argument) < ip_family(prefix))
						bitmap = 0;
					break;

				case RTGreaterEqualStrategyNumber:
				case RTGreaterStrategyNumber:
					if (ip_family(argument) > ip_family(prefix))
						bitmap = 0;
					break;

				case RTNotEqualStrategyNumber:
					break;

				default:
					/* For all other cases, we can be sure there is no match */
					bitmap = 0;
					break;
			}

			if (!bitmap)
				break;

			/* Other checks make no sense with different families. */
			continue;
		}

		/*
		 * Check 1: network bit count
		 *
		 * Network bit count (ip_bits) helps to check leaves for sub network
		 * and sup network operators.  At non-leaf nodes, we know every child
		 * value has greater ip_bits, so we can avoid descending in some cases
		 * too.
		 *
		 * This check is less expensive than checking the address bits, so we
		 * are doing this before, but it has to be done after for the basic
		 * comparison strategies, because ip_bits only affect their results
		 * when the common network bits are the same.
		 */
		switch (strategy)
		{
			case RTSubStrategyNumber:
				if (commonbits <= ip_bits(argument))
					bitmap &= (1 << 2) | (1 << 3);
				break;

			case RTSubEqualStrategyNumber:
				if (commonbits < ip_bits(argument))
					bitmap &= (1 << 2) | (1 << 3);
				break;

			case RTSuperStrategyNumber:
				if (commonbits == ip_bits(argument) - 1)
					bitmap &= 1 | (1 << 1);
				else if (commonbits >= ip_bits(argument))
					bitmap = 0;
				break;

			case RTSuperEqualStrategyNumber:
				if (commonbits == ip_bits(argument))
					bitmap &= 1 | (1 << 1);
				else if (commonbits > ip_bits(argument))
					bitmap = 0;
				break;

			case RTEqualStrategyNumber:
				if (commonbits < ip_bits(argument))
					bitmap &= (1 << 2) | (1 << 3);
				else if (commonbits == ip_bits(argument))
					bitmap &= 1 | (1 << 1);
				else
					bitmap = 0;
				break;
		}

		if (!bitmap)
			break;

		/*
		 * Check 2: common network bits
		 *
		 * Compare available common prefix bits to the query, but not beyond
		 * either the query's netmask or the minimum netmask among the
		 * represented values.  If these bits don't match the query, we can
		 * eliminate some cases.
		 */
		order = bitncmp(ip_addr(prefix), ip_addr(argument),
						Min(commonbits, ip_bits(argument)));

		if (order != 0)
		{
			switch (strategy)
			{
				case RTLessStrategyNumber:
				case RTLessEqualStrategyNumber:
					if (order > 0)
						bitmap = 0;
					break;

				case RTGreaterEqualStrategyNumber:
				case RTGreaterStrategyNumber:
					if (order < 0)
						bitmap = 0;
					break;

				case RTNotEqualStrategyNumber:
					break;

				default:
					/* For all other cases, we can be sure there is no match */
					bitmap = 0;
					break;
			}

			if (!bitmap)
				break;

			/*
			 * Remaining checks make no sense when common bits don't match.
			 */
			continue;
		}

		/*
		 * Check 3: next network bit
		 *
		 * We can filter out branch 2 or 3 using the next network bit of the
		 * argument, if it is available.
		 *
		 * This check matters for the performance of the search. The results
		 * would be correct without it.
		 */
		if (bitmap & ((1 << 2) | (1 << 3)) &&
			commonbits < ip_bits(argument))
		{
			int			nextbit;

			nextbit = ip_addr(argument)[commonbits / 8] &
				(1 << (7 - commonbits % 8));

			switch (strategy)
			{
				case RTLessStrategyNumber:
				case RTLessEqualStrategyNumber:
					if (!nextbit)
						bitmap &= 1 | (1 << 1) | (1 << 2);
					break;

				case RTGreaterEqualStrategyNumber:
				case RTGreaterStrategyNumber:
					if (nextbit)
						bitmap &= 1 | (1 << 1) | (1 << 3);
					break;

				case RTNotEqualStrategyNumber:
					break;

				default:
					if (!nextbit)
						bitmap &= 1 | (1 << 1) | (1 << 2);
					else
						bitmap &= 1 | (1 << 1) | (1 << 3);
					break;
			}

			if (!bitmap)
				break;
		}

		/*
		 * Remaining checks are only for the basic comparison strategies. This
		 * test relies on the strategy number ordering defined in stratnum.h.
		 */
		if (strategy < RTEqualStrategyNumber ||
			strategy > RTGreaterEqualStrategyNumber)
			continue;

		/*
		 * Check 4: network bit count
		 *
		 * At this point, we know that the common network bits of the prefix
		 * and the argument are the same, so we can go forward and check the
		 * ip_bits.
		 */
		switch (strategy)
		{
			case RTLessStrategyNumber:
			case RTLessEqualStrategyNumber:
				if (commonbits == ip_bits(argument))
					bitmap &= 1 | (1 << 1);
				else if (commonbits > ip_bits(argument))
					bitmap = 0;
				break;

			case RTGreaterEqualStrategyNumber:
			case RTGreaterStrategyNumber:
				if (commonbits < ip_bits(argument))
					bitmap &= (1 << 2) | (1 << 3);
				break;
		}

		if (!bitmap)
			break;

		/* Remaining checks don't make sense with different ip_bits. */
		if (commonbits != ip_bits(argument))
			continue;

		/*
		 * Check 5: next host bit
		 *
		 * We can filter out branch 0 or 1 using the next host bit of the
		 * argument, if it is available.
		 *
		 * This check matters for the performance of the search. The results
		 * would be correct without it.  There is no point in running it for
		 * leafs as we have to check the whole address on the next step.
		 */
		if (!leaf && bitmap & (1 | (1 << 1)) &&
			commonbits < ip_maxbits(argument))
		{
			int			nextbit;

			nextbit = ip_addr(argument)[commonbits / 8] &
				(1 << (7 - commonbits % 8));

			switch (strategy)
			{
				case RTLessStrategyNumber:
				case RTLessEqualStrategyNumber:
					if (!nextbit)
						bitmap &= 1 | (1 << 2) | (1 << 3);
					break;

				case RTGreaterEqualStrategyNumber:
				case RTGreaterStrategyNumber:
					if (nextbit)
						bitmap &= (1 << 1) | (1 << 2) | (1 << 3);
					break;

				case RTNotEqualStrategyNumber:
					break;

				default:
					if (!nextbit)
						bitmap &= 1 | (1 << 2) | (1 << 3);
					else
						bitmap &= (1 << 1) | (1 << 2) | (1 << 3);
					break;
			}

			if (!bitmap)
				break;
		}

		/*
		 * Check 6: whole address
		 *
		 * This is the last check for correctness of the basic comparison
		 * strategies.  It's only appropriate at leaf entries.
		 */
		if (leaf)
		{
			/* Redo ordering comparison using all address bits */
			order = bitncmp(ip_addr(prefix), ip_addr(argument),
							ip_maxbits(prefix));

			switch (strategy)
			{
				case RTLessStrategyNumber:
					if (order >= 0)
						bitmap = 0;
					break;

				case RTLessEqualStrategyNumber:
					if (order > 0)
						bitmap = 0;
					break;

				case RTEqualStrategyNumber:
					if (order != 0)
						bitmap = 0;
					break;

				case RTGreaterEqualStrategyNumber:
					if (order < 0)
						bitmap = 0;
					break;

				case RTGreaterStrategyNumber:
					if (order <= 0)
						bitmap = 0;
					break;

				case RTNotEqualStrategyNumber:
					if (order == 0)
						bitmap = 0;
					break;
			}

			if (!bitmap)
				break;
		}
	}

	return bitmap;
}