View Javadoc
1   package com.ericsson.research.transport.ws.spi;
2   
3   /*
4    * ##_BEGIN_LICENSE_##
5    * Transport Abstraction Package (trap)
6    * ----------
7    * Copyright (C) 2014 Ericsson AB
8    * ----------
9    * Redistribution and use in source and binary forms, with or without modification,
10   * are permitted provided that the following conditions are met:
11   * 
12   * 1. Redistributions of source code must retain the above copyright notice, this
13   *    list of conditions and the following disclaimer.
14   * 
15   * 2. Redistributions in binary form must reproduce the above copyright notice,
16   *    this list of conditions and the following disclaimer in the documentation
17   *    and/or other materials provided with the distribution.
18   * 
19   * 3. Neither the name of the Ericsson AB nor the names of its contributors
20   *    may be used to endorse or promote products derived from this software without
21   *    specific prior written permission.
22   * 
23   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26   * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
32   * OF THE POSSIBILITY OF SUCH DAMAGE.
33   * ##_END_LICENSE_##
34   */
35  
36  
37  import java.io.IOException;
38  import java.util.Random;
39  
40  import com.ericsson.research.transport.ws.WSException;
41  
42  public class WSHybiFrame extends WSAbstractFrame
43  {
44      
45      protected boolean           masked;
46      protected boolean           finalFragment;
47      private static final Random random = new Random();
48      
49      protected WSHybiFrame()
50      {
51      }
52      
53      public WSHybiFrame(byte type, byte[] payload, boolean masked) throws IOException
54      {
55          this(type, payload, masked, true);
56      }
57      
58      public WSHybiFrame(byte type, byte[] payload, boolean masked, boolean finalFragment) throws IOException
59      {
60          super(type);
61          this.masked = masked;
62          this.finalFragment = finalFragment;
63          int j = 0;
64          byte b;
65          if (payload == null)
66              payload = empty;
67          j = payload.length;
68          if (masked)
69          {
70              j += 4;
71              b = (byte) 0x80;
72          }
73          else
74              b = 0;
75          //FIXME: what if payload is null here?
76          if (payload.length < 126)
77          {
78              this.payload = new byte[j + 2];
79              b |= payload.length;
80              this.payload[1] = b;
81          }
82          else if (payload.length <= 0xFFFF)
83          {
84              this.payload = new byte[j + 4];
85              b |= 126;
86              this.payload[1] = b;
87              this.payload[2] = (byte) ((payload.length >>> 8) & 0xFF);
88              this.payload[3] = (byte) (payload.length & 0xFF);
89          }
90          else
91          //if (payload.length <= 0x7FFFFFFF) (Payload is always less than Int.MAX from Java)
92          {
93              this.payload = new byte[j + 10];
94              b |= 127;
95              this.payload[1] = b;
96              for (int i = 56; i >= 0; i = i - 8)
97                  this.payload[((56 - i) >>> 3) + 2] = (byte) (((long) payload.length >>> i) & 0xFF);
98          }
99          j = this.payload.length - j;
100         this.payload[0] = type;
101         if (finalFragment)
102             this.payload[0] |= 0x80;
103         if (masked)
104         {
105             byte[] mask = new byte[4];
106             random.nextBytes(mask);
107             for (int i = 0; i < 4; i++)
108                 this.payload[j++] = mask[i];
109             for (int i = 0; i < payload.length; i++)
110             {
111                 int k = i % 4;
112                 this.payload[j++] = (byte) (payload[i] ^ mask[k]);
113             }
114         }
115         else
116             System.arraycopy(payload, 0, this.payload, j, payload.length);
117     }
118     
119     public int deserialize(byte[] data, int length) throws WSException
120     {
121         if (this.l1 == -1)
122             throw new IllegalStateException("Already deserialized");
123         for (;;)
124         {
125             if (length <= this.pos)
126                 return 0;
127             switch (this.pos)
128             {
129                 case 0:
130                     this.finalFragment = ((data[0] & 0x80) == 0x80);
131                     this.type = (byte) (data[0] & 0x0F);
132                     this.pos++;
133                     break;
134                 case 1:
135                     this.masked = ((data[1] & 0x80) == 0x80);
136                     this.l1 = (byte) (data[1] & 0x7F);
137                     switch (this.l1)
138                     {
139                         case 127:
140                             this.pos += 8;
141                             this.l1 = 10;
142                             break;
143                         case 126:
144                             this.pos += 2;
145                             this.l1 = 4;
146                             break;
147                         default:
148                             if (this.len == 0)
149                             {
150                                 this.payload = empty;
151                                 this.l1 = -1;
152                                 return 2;
153                             }
154                             this.len = this.l1;
155                             this.pos += this.len;
156                             this.l1 = 2;
157                     }
158                     if (this.masked)
159                         this.pos += 4;
160                     break;
161                 default:
162                     if (this.len == -1)
163                     {
164                         switch (this.l1)
165                         {
166                             case 4:
167                                 this.len = ((data[2] << 8) & 0xFF00) | (data[3] & 0xFF);
168                                 break;
169                             case 10:
170                                 this.len = data[2];
171                                 if ((this.len & 0x80) == 0x80)
172                                     throw new WSException("Invalid frame length");
173                                 for (int i = 3; i < 10; i++)
174                                     this.len = ((this.len << 8) & 0xFFFFFF00) | (data[i] & 0xFF);
175                         }
176                         this.pos += this.len;
177                     }
178                     else
179                     {
180                         // here l1 points to the position of the mask or payload in the buffer
181                         this.payload = new byte[this.len];
182                         System.arraycopy(data, this.l1 + (this.masked ? 4 : 0), this.payload, 0, this.len);
183                         if (this.masked)
184                             for (int i = 0; i < this.len; i++)
185                                 this.payload[i] = (byte) (this.payload[i] ^ data[this.l1 + (i % 4)]);
186                         this.l1 = -1;
187                         return this.pos + 1;
188                     }
189             }
190         }
191     }
192     
193 }