Bug-1370: Reads message body bytes as well as exception is thrown during parsing.
[bgpcep.git] / bgp / parser-spi / src / main / java / org / opendaylight / protocol / bgp / parser / spi / AbstractMessageRegistry.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. 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.protocol.bgp.parser.spi;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.primitives.UnsignedBytes;
12 import io.netty.buffer.ByteBuf;
13 import java.util.Arrays;
14 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
15 import org.opendaylight.protocol.bgp.parser.BGPError;
16 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
17 import org.opendaylight.protocol.util.ByteArray;
18 import org.opendaylight.yangtools.yang.binding.Notification;
19
20 public abstract class AbstractMessageRegistry implements MessageRegistry {
21
22     private static final byte[] MARKER;
23
24     protected abstract Notification parseBody(final int type, final ByteBuf body, final int messageLength) throws BGPDocumentedException;
25
26     protected abstract void serializeMessageImpl(final Notification message, final ByteBuf buffer);
27
28     static {
29         MARKER = new byte[MessageUtil.MARKER_LENGTH];
30         Arrays.fill(MARKER, UnsignedBytes.MAX_VALUE);
31     }
32
33     @Override
34     public final Notification parseMessage(final ByteBuf buffer) throws BGPDocumentedException, BGPParsingException {
35         Preconditions.checkArgument(buffer != null && buffer.isReadable(), "Array of bytes cannot be null or empty.");
36         Preconditions.checkArgument(buffer.readableBytes() >= MessageUtil.COMMON_HEADER_LENGTH,
37                 "Too few bytes in passed array. Passed: %s. Expected: >= %s.", buffer.readableBytes(), MessageUtil.COMMON_HEADER_LENGTH);
38         final byte[] marker = ByteArray.readBytes(buffer, MessageUtil.MARKER_LENGTH);
39
40         if (!Arrays.equals(marker, MARKER)) {
41             throw new BGPDocumentedException("Marker not set to ones.", BGPError.CONNECTION_NOT_SYNC);
42         }
43         final int messageLength = buffer.readUnsignedShort();
44         // to be sent with Error message
45         final byte typeBytes = buffer.readByte();
46         final int messageType = UnsignedBytes.toInt(typeBytes);
47
48         final ByteBuf msgBody = buffer.slice(buffer.readerIndex(), messageLength - MessageUtil.COMMON_HEADER_LENGTH);
49
50         if (messageLength < MessageUtil.COMMON_HEADER_LENGTH) {
51             throw BGPDocumentedException.badMessageLength("Message length field not within valid range.", messageLength);
52         }
53         if (msgBody.readableBytes() != messageLength - MessageUtil.COMMON_HEADER_LENGTH) {
54             throw new BGPParsingException("Size doesn't match size specified in header. Passed: " + msgBody.readableBytes()
55                     + "; Expected: " + (messageLength - MessageUtil.COMMON_HEADER_LENGTH) + ". ");
56         }
57         Notification msg = null;
58         try {
59             msg = parseBody(messageType, msgBody, messageLength);
60         } finally {
61             // Always reads body bytes
62             buffer.skipBytes(messageLength - MessageUtil.COMMON_HEADER_LENGTH);
63         }
64         if (msg == null) {
65             throw new BGPDocumentedException("Unhandled message type " + messageType, BGPError.BAD_MSG_TYPE, new byte[] { typeBytes });
66         }
67         return msg;
68     }
69
70     @Override
71     public final void serializeMessage(final Notification message, final ByteBuf buffer) {
72         Preconditions.checkNotNull(message, "BGPMessage is mandatory.");
73         serializeMessageImpl(message, buffer);
74     }
75 }