/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tajo.common.type;
import org.apache.hadoop.io.Writable;
import org.apache.tajo.common.exception.InvalidAddressException;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.StringTokenizer;
public class IPv4 implements Writable, Comparable<IPv4> {
public static IPv4 getSubnetMask(int len) {
byte[] bytes = new byte[4];
int index = 0;
while (len > 7) {
len -= 8;
bytes[index++] = (byte)0xFF;
}
bytes[index] = (byte)((0xFF >> (8-len)) << (8-len));
return new IPv4(bytes);
}
private byte[] ipBytes;
public IPv4() {
this.ipBytes = new byte[4];
}
public IPv4(byte[] bytes) {
this.ipBytes = new byte[4];
set(bytes);
}
public IPv4(String ipAddress) throws InvalidAddressException {
this.ipBytes = new byte[4];
this.set(ipAddress);
}
public void set(String ipAddress) throws InvalidAddressException {
StringTokenizer tokenizer = new StringTokenizer(ipAddress);
String token;
for (int i = 0; i < 4; i++) {
token = tokenizer.nextToken(".");
if (token == null) {
throw new InvalidAddressException();
} else if (Integer.parseInt(token) < 0 || Integer.parseInt(token) > 255) {
throw new InvalidAddressException();
}
// ipBytes[i] = Short.valueOf(token).byteValue();
this.ipBytes[i] = (byte)(((Integer.parseInt(token) << 24) >> 24) & 0xFF);
}
}
public void set(byte[] bytes) {
if (this.ipBytes == null) {
this.ipBytes = new byte[4];
}
System.arraycopy(bytes, 0, this.ipBytes, 0, 4);
}
public byte[] getBytes() {
return this.ipBytes;
}
/**
* This function will be provided as UDF later.
* @param addr
* @return
* @throws InvalidAddressException
*/
public boolean matchSubnet(String addr) throws InvalidAddressException {
int maskIndex;
if ((maskIndex=addr.indexOf('/')) != -1) {
IPv4 other = new IPv4(addr.substring(0, maskIndex));
int maskLen = Integer.parseInt(addr.substring(maskIndex+1));
IPv4 subnetMask = IPv4.getSubnetMask(maskLen);
if (this.and(subnetMask).equals(other.and(subnetMask))) {
return true;
} else {
return false;
}
} else {
throw new InvalidAddressException();
}
}
/**
* This function will be provided as UDF later.
* @return
*/
public boolean matchGeoIP(/* country code */) {
return false;
}
public IPv4 and(IPv4 other) {
byte[] res = new byte[4];
byte[] obytes = other.getBytes();
for (int i = 0; i < 4; i++) {
res[i] = (byte)(this.ipBytes[i] & obytes[i]);
}
return new IPv4(res);
}
@Override
public boolean equals(Object o) {
if (o instanceof IPv4) {
byte[] obytes = ((IPv4)o).getBytes();
for (int i = 0; i < 4; i++) {
if (this.ipBytes[i] != obytes[i]) {
return false;
}
}
return true;
}
return false;
}
/**
* This is a method for range query such as 'SELECT * FROM table WHERE srcIP > 163.152.23.0 and srcIP < 163.152.23.100'
*/
@Override
public int compareTo(IPv4 o) {
byte[] obytes = o.getBytes();
for (int i = 0; i < 4; i++) {
if (this.ipBytes[i] > obytes[i]) {
return 1;
} else if (this.ipBytes[i] < obytes[i]) {
return -1;
}
}
return 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
int i;
for (i = 0; i < 3; i++) {
sb.append(((int)ipBytes[i] << 24) >> 24 & 0xFF).append(".");
}
sb.append(((int)ipBytes[i] << 24) >> 24 & 0xFF);
return sb.toString();
}
@Override
public int hashCode() {
return 0;
}
@Override
public void readFields(DataInput in) throws IOException {
in.readFully(this.ipBytes, 0, 4);
}
@Override
public void write(DataOutput out) throws IOException {
out.write(this.ipBytes, 0, 4);
}
}