BUG-2825: remove unused calculation
[mdsal.git] / model / ietf / ietf-type-util / src / main / java / org / opendaylight / mdsal / model / ietf / util / Ipv6Utils.java
1 /*
2  * Copyright (c) 2016 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.model.ietf.util;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.base.Verify;
12 import javax.annotation.Nonnull;
13
14 /**
15  * IPv6 address parsing for ietf-inet-types ipv6-address and ipv6-prefix. This is an internal implementation
16  * class, not meant to be exposed in any shape or form to the outside world, as the code relies on the fact that
17  * the strings presented to it have been previously validated to conform to the regular expressions defined in
18  * the YANG model.
19  */
20 /*
21  * v6 routines added by Anton Ivanov on 14.6.2015
22  * revised by Robert Varga
23  *
24  * BIG FAT WARNING!!!
25  * Read all of the following before you touch any v6 code or decide to
26  * optimize it by invoking a "simple" Guava call
27  *
28  * Java IPv6 is fundamentally broken and Google libraries do not fix it.
29  * 1. Java will allways implicitly rewrite v4 mapped into v6 as a v4 address
30  *      and there is absolutely no way to override this behaviour
31  * 2. Guava libraries cannot parse non-canonical IPv6. They will throw an
32  *      exception. Even if they did, they re-use the same broken java code
33  *      underneath.
34  *
35  * This is why we have to parse v6 by ourselves.
36  *
37  * The following conversion code is based on inet_cidr_pton_ipv6 in NetBSD
38  *
39  * The original BSD code is licensed under standard BSD license. While we
40  * are not obliged to provide an attribution, credit where credit is due.
41  * As far as why it is similar to Sun's sun.net.util please ask Sun why
42  * their code has the same variable names, comments and code flow.
43  */
44 final class Ipv6Utils {
45     private static final int INADDR4SZ = 4;
46     private static final int INADDR6SZ = 16;
47     private static final int INT16SZ = Short.BYTES;
48
49     private Ipv6Utils() {
50         throw new UnsupportedOperationException();
51     }
52
53     /**
54      * Convert Ipv6Address object to a valid Canonical v6 address in byte format
55      *
56      * @param addrStr IPv6 address string
57      * @return byte array of size 16 containing the binary IPv6 address
58      * @throws NullPointerException if ipv6address is null
59      */
60    public static @Nonnull byte[] bytesForString(final @Nonnull String addrStr) {
61        final int percentPos = addrStr.indexOf('%');
62        final int addrStrLen = percentPos == -1 ? addrStr.length() : percentPos;
63
64        /* Leading :: requires some special handling. */
65        int i = 0;
66        if (addrStr.charAt(i) == ':') {
67            // Note ++i side-effect in check
68            Preconditions.checkArgument(addrStr.charAt(++i) == ':', "Invalid v6 address '%s'", addrStr);
69        }
70
71        final byte[] dst = new byte[INADDR6SZ];
72
73        boolean saw_xdigit = false;
74        int val = 0;
75        int colonp = -1;
76        int j = 0;
77        int curtok = i;
78        while (i < addrStrLen) {
79            final char ch = addrStr.charAt(i++);
80
81            /* v6 separator */
82            if (ch == ':') {
83                curtok = i;
84                if (!saw_xdigit) {
85                    /* no need to check separator position validity - regexp does that */
86                    colonp = j;
87                    continue;
88                }
89
90                /* removed overrun check - the regexp checks for valid data */
91
92                dst[j++] = (byte) ((val >>> 8) & 0xff);
93                dst[j++] = (byte) (val & 0xff);
94                saw_xdigit = false;
95                val = 0;
96                continue;
97            }
98
99            /* frankenstein - v4 attached to v6, mixed notation */
100            if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
101
102                /*
103                 * This has passed the regexp so it is fairly safe to parse it
104                 * straight away. Use the Ipv4Utils for that.
105                 */
106                Ipv4Utils.fillIpv4Bytes(dst, j, addrStr, curtok, addrStrLen);
107                j += INADDR4SZ;
108                saw_xdigit = false;
109                break;
110            }
111
112            /* Business as usual - ipv6 address digit.
113             * We can remove all checks from the original BSD code because
114             * the regexp has already verified that we are not being fed
115             * anything bigger than 0xffff between the separators.
116             */
117            final int chval = AbstractIetfYangUtil.hexValue(ch);
118            val = (val << 4) | chval;
119            saw_xdigit = true;
120        }
121
122        if (saw_xdigit) {
123            Verify.verify(j + INT16SZ <= INADDR6SZ, "Overrun in parsing of '%s', should not occur", addrStr);
124            dst[j++] = (byte) ((val >> 8) & 0xff);
125            dst[j++] = (byte) (val & 0xff);
126        }
127
128        if (colonp != -1) {
129            Verify.verify(j != INADDR6SZ, "Overrun in parsing of '%s', should not occur", addrStr);
130
131            final int n = j - colonp;
132            for (i = 1; i <= n; i++) {
133                dst[INADDR6SZ - i] = dst[j - i];
134                dst[j - i] = 0;
135            }
136        } else {
137            Verify.verify(j == INADDR6SZ, "Overrun in parsing of '%s', should not occur", addrStr);
138        }
139
140        return dst;
141    }
142 }