summaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/fs4/Packet.java
blob: 1b61c35ae66a0b58b8fc92a41226d3183e72efbc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.fs4;

import java.nio.ByteBuffer;
import java.util.logging.Logger;

/**
 * Superclass of fs4 packets containing channel/query ID
 *
 * @author bratseth
 */
public abstract class Packet extends BasicPacket {
    private static Logger log = Logger.getLogger(Packet.class.getName());
    /**
     * The channel at which this packet will be sent or was received,
     * or -1 when this is not known
     */
    protected int channel=-1;

    protected static final int CHANNEL_ID_OFFSET = 8;

    /**
     * Fills this package from a byte buffer positioned at the first
     * byte of the package
     *
     * @return this Packet (as a BasicPacket) for convenience
     * @throws UnsupportedOperationException if not implemented in the subclass
     */
    public BasicPacket decode(ByteBuffer buffer) {
        int originalPos = buffer.position();
        length=buffer.getInt()+4; // Streamed packet length is the length-4
        int packetLength = length;
        try {
            int code=buffer.getInt();
            channel=buffer.getInt();

            decodeAndDecompressBody(buffer, code, length - 3*4);
        }
        finally {
            int targetPosition = (originalPos + packetLength);
            if (buffer.position() != targetPosition) {
                log.warning(" position in buffer, is "
                            + buffer.position()
                            + " should be "
                            + targetPosition);
                buffer.position(targetPosition);
            }
        }

        return this;
    }

    /**
     * <p>Encodes this package onto the given buffer at the current
     * position.  The position of the buffer after encoding is the
     * byte following the last encoded byte.</p>
     *
     * <p>This method will ensure that everything is written provided
     * sufficient capacity regardless of the buffer limit.
     * When returning, the limit is at the end of the package (qual to the
     * position).</p>
     *
     * @return this for convenience
     * @throws UnsupportedOperationException if not implemented in the subclass
     */
    public final Packet encode(ByteBuffer buffer, int channel) throws BufferTooSmallException {
        this.channel=channel;
        int oldLimit = buffer.limit();
        int startPosition = buffer.position();

        buffer.limit(buffer.capacity());
        try {
            buffer.putInt(8); // Real length written later, when we know it
            buffer.putInt(getCode());
            buffer.putInt(channel);

            encodeAndCompressBody(buffer, startPosition);
        }
        catch (java.nio.BufferOverflowException e) {
            // reset buffer to expected state
            buffer.position(startPosition);
            buffer.limit(oldLimit);
            throw new BufferTooSmallException("Destination buffer too small while encoding packet");
        }
        return this;
    }

    /**
     * Get the channel id of the packet.  In the FS4 transport protocol,
     * there is the concept of a channel.  This must <b>not</b> be confused
     * with all the other channels we have floating around this code (aargh!).
     * <P>
     * The channel can be thought of as a way to pair up requests and
     * responses in the FS4 protocol:  A response always belongs to
     * to a channel and it is the clients responsibility to not re-use
     * channel ids within the same connection.
     * <p>
     * Summary: This "channel" means "session id"
     *
     * @return FS4 channel id
     *
     */
    public int getChannel() { return channel; }

    public void setChannel(int channel) { this.channel=channel; }


    /** Informs that this packets needs a channel ID. */
    public boolean hasChannelId() {
        return true;
    }

    /**
     * Only for use with encodingBuffer magic.
     *
     * This is only called from allocateAndEncode and grantEncodingBuffer,
     * therefore an assumption about the packet starting at the beginning of the
     * buffer is made.
     */
    protected void patchChannelId(ByteBuffer buf, int channelId) {
        buf.putInt(CHANNEL_ID_OFFSET, channelId);
    }

    public String toString() {
        return "packet with code " + getCode() + ", channelId=" + getChannel();
    }

}