/** * Copyright 2011 Google Inc. * * Licensed 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 com.google.bitcoin.core; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Date; import static com.google.bitcoin.core.Utils.uint32ToByteStreamLE; import static com.google.bitcoin.core.Utils.uint64ToByteStreamLE; /** * A PeerAddress holds an IP address and port number representing the network location of * a peer in the BitCoin P2P network. It exists primarily for serialization purposes. */ public class PeerAddress extends Message { private static final long serialVersionUID = 7501293709324197411L; InetAddress addr; int port; BigInteger services; long time; public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException { super(params, payload, offset, protocolVersion); } public PeerAddress(InetAddress addr, int port, int protocolVersion) { this.addr = addr; this.port = port; this.protocolVersion = protocolVersion; } public void bitcoinSerializeToStream(OutputStream stream) throws IOException { if (protocolVersion >= 31402) { int secs = (int)(new Date().getTime() / 1000); uint32ToByteStreamLE(secs, stream); } uint64ToByteStreamLE(BigInteger.ZERO, stream); // nServices. // Java does not provide any utility to map an IPv4 address into IPv6 space, so we have to do it by hand. byte[] ipBytes = addr.getAddress(); if (ipBytes.length == 4) { byte[] v6addr = new byte[16]; System.arraycopy(ipBytes, 0, v6addr, 12, 4); v6addr[10] = (byte) 0xFF; v6addr[11] = (byte) 0xFF; ipBytes = v6addr; } stream.write(ipBytes); // And write out the port. stream.write((byte) (0xFF & port)); stream.write((byte) (0xFF & (port >> 8))); } @Override protected void parse() throws ProtocolException { // Format of a serialized address: // uint32 timestamp // uint64 services (flags determining what the node can do) // 16 bytes ip address // 2 bytes port num if (protocolVersion > 31402) time = readUint32(); else time = -1; services = readUint64(); byte[] addrBytes = readBytes(16); try { addr = InetAddress.getByAddress(addrBytes); } catch (UnknownHostException e) { throw new RuntimeException(e); // Cannot happen. } port = ((0xFF & bytes[cursor++]) << 8) | (0xFF & bytes[cursor++]); } @Override public String toString() { return "[" + addr.getHostAddress() + "]:" + port; } }