View Javadoc
1   /*
2    * Copyright 2015 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel.unix;
17  
18  import java.net.Inet6Address;
19  import java.net.InetAddress;
20  import java.net.InetSocketAddress;
21  import java.net.UnknownHostException;
22  
23  /**
24   * <strong>Internal usage only!</strong>
25   */
26  public final class NativeInetAddress {
27      private static final byte[] IPV4_MAPPED_IPV6_PREFIX = {
28              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
29      final byte[] address;
30      final int scopeId;
31  
32      public static NativeInetAddress newInstance(InetAddress addr) {
33          byte[] bytes = addr.getAddress();
34          if (addr instanceof Inet6Address) {
35              return new NativeInetAddress(bytes, ((Inet6Address) addr).getScopeId());
36          } else {
37              // convert to ipv4 mapped ipv6 address;
38              return new NativeInetAddress(ipv4MappedIpv6Address(bytes));
39          }
40      }
41  
42      public NativeInetAddress(byte[] address, int scopeId) {
43          this.address = address;
44          this.scopeId = scopeId;
45      }
46  
47      public NativeInetAddress(byte[] address) {
48          this(address, 0);
49      }
50  
51      public byte[] address() {
52          return address;
53      }
54  
55      public int scopeId() {
56          return scopeId;
57      }
58  
59      public static byte[] ipv4MappedIpv6Address(byte[] ipv4) {
60          byte[] address = new byte[16];
61          System.arraycopy(IPV4_MAPPED_IPV6_PREFIX, 0, address, 0, IPV4_MAPPED_IPV6_PREFIX.length);
62          System.arraycopy(ipv4, 0, address, 12, ipv4.length);
63          return address;
64      }
65  
66      public static InetSocketAddress address(byte[] addr, int offset, int len) {
67          // The last 4 bytes are always the port
68          final int port = decodeInt(addr, offset + len - 4);
69          final InetAddress address;
70  
71          try {
72              switch (len) {
73                  // 8 bytes:
74                  // - 4  == ipaddress
75                  // - 4  == port
76                  case 8:
77                      byte[] ipv4 = new byte[4];
78                      System.arraycopy(addr, offset, ipv4, 0, 4);
79                      address = InetAddress.getByAddress(ipv4);
80                      break;
81  
82                  // 24 bytes:
83                  // - 16  == ipaddress
84                  // - 4   == scopeId
85                  // - 4   == port
86                  case 24:
87                      byte[] ipv6 = new byte[16];
88                      System.arraycopy(addr, offset, ipv6, 0, 16);
89                      int scopeId = decodeInt(addr, offset + len  - 8);
90                      address = Inet6Address.getByAddress(null, ipv6, scopeId);
91                      break;
92                  default:
93                      throw new Error();
94              }
95              return new InetSocketAddress(address, port);
96          } catch (UnknownHostException e) {
97              throw new Error("Should never happen", e);
98          }
99      }
100 
101     static int decodeInt(byte[] addr, int index) {
102         return  (addr[index]     & 0xff) << 24 |
103                 (addr[index + 1] & 0xff) << 16 |
104                 (addr[index + 2] & 0xff) <<  8 |
105                 addr[index + 3] & 0xff;
106     }
107 }