1/*
2 * Copyright (C) 2012 Square, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.squareup.okhttp.internal.spdy;
17
18final class Settings {
19  /**
20   * From the spdy/3 spec, the default initial window size for all streams is
21   * 64 KiB. (Chrome 25 uses 10 MiB).
22   */
23  static final int DEFAULT_INITIAL_WINDOW_SIZE = 64 * 1024;
24
25  /** Peer request to clear durable settings. */
26  static final int FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x1;
27
28  /** Sent by servers only. The peer requests this setting persisted for future connections. */
29  static final int PERSIST_VALUE = 0x1;
30  /** Sent by clients only. The client is reminding the server of a persisted value. */
31  static final int PERSISTED = 0x2;
32
33  /** Sender's estimate of max incoming kbps. */
34  static final int UPLOAD_BANDWIDTH = 0x1;
35  /** Sender's estimate of max outgoing kbps. */
36  static final int DOWNLOAD_BANDWIDTH = 0x2;
37  /** Sender's estimate of milliseconds between sending a request and receiving a response. */
38  static final int ROUND_TRIP_TIME = 0x3;
39  /** Sender's maximum number of concurrent streams. */
40  static final int MAX_CONCURRENT_STREAMS = 0x4;
41  /** Current CWND in Packets. */
42  static final int CURRENT_CWND = 0x5;
43  /** Retransmission rate. Percentage */
44  static final int DOWNLOAD_RETRANS_RATE = 0x6;
45  /** Window size in bytes. */
46  static final int INITIAL_WINDOW_SIZE = 0x7;
47  /** Window size in bytes. */
48  static final int CLIENT_CERTIFICATE_VECTOR_SIZE = 0x8;
49  /** Total number of settings. */
50  static final int COUNT = 0x9;
51
52  /** Bitfield of which flags that values. */
53  private int set;
54
55  /** Bitfield of flags that have {@link #PERSIST_VALUE}. */
56  private int persistValue;
57
58  /** Bitfield of flags that have {@link #PERSISTED}. */
59  private int persisted;
60
61  /** Flag values. */
62  private final int[] values = new int[COUNT];
63
64  void set(int id, int idFlags, int value) {
65    if (id >= values.length) {
66      return; // Discard unknown settings.
67    }
68
69    int bit = 1 << id;
70    set |= bit;
71    if ((idFlags & PERSIST_VALUE) != 0) {
72      persistValue |= bit;
73    } else {
74      persistValue &= ~bit;
75    }
76    if ((idFlags & PERSISTED) != 0) {
77      persisted |= bit;
78    } else {
79      persisted &= ~bit;
80    }
81
82    values[id] = value;
83  }
84
85  /** Returns true if a value has been assigned for the setting {@code id}. */
86  boolean isSet(int id) {
87    int bit = 1 << id;
88    return (set & bit) != 0;
89  }
90
91  /** Returns the value for the setting {@code id}, or 0 if unset. */
92  int get(int id) {
93    return values[id];
94  }
95
96  /** Returns the flags for the setting {@code id}, or 0 if unset. */
97  int flags(int id) {
98    int result = 0;
99    if (isPersisted(id)) result |= Settings.PERSISTED;
100    if (persistValue(id)) result |= Settings.PERSIST_VALUE;
101    return result;
102  }
103
104  /** Returns the number of settings that have values assigned. */
105  int size() {
106    return Integer.bitCount(set);
107  }
108
109  int getUploadBandwidth(int defaultValue) {
110    int bit = 1 << UPLOAD_BANDWIDTH;
111    return (bit & set) != 0 ? values[UPLOAD_BANDWIDTH] : defaultValue;
112  }
113
114  int getDownloadBandwidth(int defaultValue) {
115    int bit = 1 << DOWNLOAD_BANDWIDTH;
116    return (bit & set) != 0 ? values[DOWNLOAD_BANDWIDTH] : defaultValue;
117  }
118
119  int getRoundTripTime(int defaultValue) {
120    int bit = 1 << ROUND_TRIP_TIME;
121    return (bit & set) != 0 ? values[ROUND_TRIP_TIME] : defaultValue;
122  }
123
124  int getMaxConcurrentStreams(int defaultValue) {
125    int bit = 1 << MAX_CONCURRENT_STREAMS;
126    return (bit & set) != 0 ? values[MAX_CONCURRENT_STREAMS] : defaultValue;
127  }
128
129  int getCurrentCwnd(int defaultValue) {
130    int bit = 1 << CURRENT_CWND;
131    return (bit & set) != 0 ? values[CURRENT_CWND] : defaultValue;
132  }
133
134  int getDownloadRetransRate(int defaultValue) {
135    int bit = 1 << DOWNLOAD_RETRANS_RATE;
136    return (bit & set) != 0 ? values[DOWNLOAD_RETRANS_RATE] : defaultValue;
137  }
138
139  int getInitialWindowSize(int defaultValue) {
140    int bit = 1 << INITIAL_WINDOW_SIZE;
141    return (bit & set) != 0 ? values[INITIAL_WINDOW_SIZE] : defaultValue;
142  }
143
144  int getClientCertificateVectorSize(int defaultValue) {
145    int bit = 1 << CLIENT_CERTIFICATE_VECTOR_SIZE;
146    return (bit & set) != 0 ? values[CLIENT_CERTIFICATE_VECTOR_SIZE] : defaultValue;
147  }
148
149  /**
150   * Returns true if this user agent should use this setting in future SPDY
151   * connections to the same host.
152   */
153  boolean persistValue(int id) {
154    int bit = 1 << id;
155    return (persistValue & bit) != 0;
156  }
157
158  /** Returns true if this setting was persisted. */
159  boolean isPersisted(int id) {
160    int bit = 1 << id;
161    return (persisted & bit) != 0;
162  }
163
164  /**
165   * Writes {@code other} into this. If any setting is populated by this and
166   * {@code other}, the value and flags from {@code other} will be kept.
167   */
168  void merge(Settings other) {
169    for (int i = 0; i < COUNT; i++) {
170      if (!other.isSet(i)) continue;
171      set(i, other.flags(i), other.get(i));
172    }
173  }
174}
175