/* * 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); }
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; }
/* * 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(); }
/* * 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; }