001 /**
002 * Copyright (C) 2009-2013 Barchart, Inc. <http://www.barchart.com/>
003 *
004 * All rights reserved. Licensed under the OSI BSD License.
005 *
006 * http://www.opensource.org/licenses/bsd-license.php
007 */
008 package com.barchart.udt;
009
010 import static com.barchart.udt.OptionUDT.Format.*;
011
012 import java.util.List;
013 import java.util.concurrent.CopyOnWriteArrayList;
014
015 import org.slf4j.Logger;
016 import org.slf4j.LoggerFactory;
017
018 import com.barchart.udt.util.HelpUDT;
019
020 /**
021 * The Enum OptionUDT.
022 * <p>
023 * provide 2 names: 1) UDT original and 2) human-readble
024 * <p>
025 * keep code values in sync with udt.h - UDT::UDTOpt; enum starts with index 0
026 *
027 * @see <a href="http://udt.sourceforge.net/udt4/doc/opt.htm">udt options</a>
028 * <pre>
029 * UDT_MSS, // the Maximum Transfer Unit
030 * UDT_SNDSYN, // if sending is blocking
031 * UDT_RCVSYN, // if receiving is blocking
032 * UDT_CC, // custom congestion control algorithm
033 * UDT_FC, // Flight flag size (window size)
034 * UDT_SNDBUF, // maximum buffer in sending queue
035 * UDT_RCVBUF, // UDT receiving buffer size
036 * UDT_LINGER, // waiting for unsent data when closing
037 * UDP_SNDBUF, // UDP sending buffer size
038 * UDP_RCVBUF, // UDP receiving buffer size
039 * UDT_MAXMSG, // maximum datagram message size
040 * UDT_MSGTTL, // time-to-live of a datagram message
041 * UDT_RENDEZVOUS, // rendezvous connection mode
042 * UDT_SNDTIMEO, // send() timeout
043 * UDT_RCVTIMEO, // recv() timeout
044 * UDT_REUSEADDR, // reuse an existing port or create a new one
045 * UDT_MAXBW, // maximum bandwidth (bytes per second) that the connection can use
046 * UDT_STATE, // current socket state, see UDTSTATUS, read only
047 * UDT_EVENT, // current avalable events associated with the socket
048 * UDT_SNDDATA, // size of data in the sending buffer
049 * UDT_RCVDATA // size of data available for recv
050 * </pre>
051 */
052 public class OptionUDT<T> {
053
054 static {
055 log = LoggerFactory.getLogger(OptionUDT.class);
056 values = new CopyOnWriteArrayList<OptionUDT<?>>();
057 }
058
059 /** the Maximum Transfer Unit. */
060 public static final OptionUDT<Integer> UDT_MSS = //
061 NEW(0, Integer.class, DECIMAL);
062 /** the Maximum Transfer Unit., bytes */
063 public static final OptionUDT<Integer> Maximum_Transfer_Unit = //
064 NEW(0, Integer.class, DECIMAL);
065
066 /** if sending is blocking. */
067 public static final OptionUDT<Boolean> UDT_SNDSYN = //
068 NEW(1, Boolean.class, BOOLEAN);
069 /** if sending is blocking., true/false */
070 public static final OptionUDT<Boolean> Is_Send_Synchronous = //
071 NEW(1, Boolean.class, BOOLEAN);
072
073 /** if receiving is blocking. */
074 public static final OptionUDT<Boolean> UDT_RCVSYN = //
075 NEW(2, Boolean.class, BOOLEAN);
076 /** if receiving is blocking, true/false */
077 public static final OptionUDT<Boolean> Is_Receive_Synchronous = //
078 NEW(2, Boolean.class, BOOLEAN);
079
080 /** custom congestion control algorithm */
081 @SuppressWarnings("rawtypes")
082 public static final OptionUDT<FactoryUDT> UDT_CC = //
083 NEW(3, FactoryUDT.class, DEFAULT);
084 /** custom congestion control algorithm, class factory */
085 @SuppressWarnings("rawtypes")
086 public static final OptionUDT<FactoryUDT> Custom_Congestion_Control = //
087 NEW(3, FactoryUDT.class, DEFAULT);
088
089 /** Flight flag size (window size). */
090 public static final OptionUDT<Integer> UDT_FC = //
091 NEW(4, Integer.class, BINARY);
092 /** Flight flag size (window size), bytes */
093 public static final OptionUDT<Integer> Flight_Window_Size = //
094 NEW(4, Integer.class, BINARY);
095
096 /** maximum buffer in sending queue. */
097 public static final OptionUDT<Integer> UDT_SNDBUF = //
098 NEW(5, Integer.class, DECIMAL);
099 /** maximum buffer in sending queue. */
100 public static final OptionUDT<Integer> Protocol_Send_Buffer_Size = //
101 NEW(5, Integer.class, DECIMAL);
102
103 /** UDT receiving buffer size. */
104 public static final OptionUDT<Integer> UDT_RCVBUF = //
105 NEW(6, Integer.class, DECIMAL);
106 /** UDT receiving buffer size limit, bytes */
107 public static final OptionUDT<Integer> Protocol_Receive_Buffer_Size = //
108 NEW(6, Integer.class, DECIMAL);
109
110 /** waiting for unsent data when closing. */
111 public static final OptionUDT<LingerUDT> UDT_LINGER = //
112 NEW(7, LingerUDT.class, DECIMAL);
113 /** waiting for unsent data when closing. true/false and timeout, seconds */
114 public static final OptionUDT<LingerUDT> Time_To_Linger_On_Close = //
115 NEW(7, LingerUDT.class, DECIMAL);
116
117 /** UDP sending buffer size. */
118 public static final OptionUDT<Integer> UDP_SNDBUF = //
119 NEW(8, Integer.class, DECIMAL);
120 /** UDP sending buffer size limit, bytes */
121 public static final OptionUDT<Integer> System_Send_Buffer_Size = //
122 NEW(8, Integer.class, DECIMAL);
123
124 /** UDP receiving buffer size. */
125 public static final OptionUDT<Integer> UDP_RCVBUF = //
126 NEW(9, Integer.class, DECIMAL);
127 /** UDP receiving buffer size limit, bytes */
128 public static final OptionUDT<Integer> System_Receive_Buffer_Size = //
129 NEW(9, Integer.class, DECIMAL);
130
131 /* maximum datagram message size */
132 // UDT_MAXMSG(10, Integer.class, DECIMAL); no support in udt core
133
134 /* time-to-live of a datagram message */
135 // UDT_MSGTTL(11, Integer.class, DECIMAL); no support in udt core
136
137 /** rendezvous connection mode. */
138 public static final OptionUDT<Boolean> UDT_RENDEZVOUS = //
139 NEW(12, Boolean.class, BOOLEAN);
140 /** rendezvous connection mode, enabled/disabled */
141 public static final OptionUDT<Boolean> Is_Randezvous_Connect_Enabled = //
142 NEW(12, Boolean.class, BOOLEAN);
143
144 /** send() timeout. */
145 public static final OptionUDT<Integer> UDT_SNDTIMEO = //
146 NEW(13, Integer.class, DECIMAL);
147 /** send() timeout. milliseconds */
148 public static final OptionUDT<Integer> Send_Timeout = //
149 NEW(13, Integer.class, DECIMAL);
150
151 /** recv() timeout. */
152 public static final OptionUDT<Integer> UDT_RCVTIMEO = //
153 NEW(14, Integer.class, DECIMAL);
154 /** recv() timeout. milliseconds */
155 public static final OptionUDT<Integer> Receive_Timeout = //
156 NEW(14, Integer.class, DECIMAL);
157
158 /** reuse an existing port or create a one. */
159 public static final OptionUDT<Boolean> UDT_REUSEADDR = //
160 NEW(15, Boolean.class, BOOLEAN);
161 /** reuse an existing port or create a one. true/false */
162 public static final OptionUDT<Boolean> Is_Address_Reuse_Enabled = //
163 NEW(15, Boolean.class, BOOLEAN);
164
165 /** maximum bandwidth (bytes per second) that the connection can use. */
166 public static final OptionUDT<Long> UDT_MAXBW = //
167 NEW(16, Long.class, DECIMAL);
168 /** maximum bandwidth (bytes per second) that the connection can use. */
169 public static final OptionUDT<Long> Maximum_Bandwidth = //
170 NEW(16, Long.class, DECIMAL);
171
172 /** current socket state, see UDTSTATUS, read only */
173 public static final OptionUDT<Integer> UDT_STATE = //
174 NEW(17, Integer.class, DECIMAL);
175 /** current socket status code, see {@link StatusUDT#getCode()}, read only */
176 public static final OptionUDT<Integer> Status_Code = //
177 NEW(17, Integer.class, DECIMAL);
178
179 /** current available events associated with the socket */
180 public static final OptionUDT<Integer> UDT_EVENT = //
181 NEW(18, Integer.class, DECIMAL);
182 /** current available epoll events, see {@link EpollUDT.Opt#code} */
183 public static final OptionUDT<Integer> Epoll_Event_Mask = //
184 NEW(18, Integer.class, DECIMAL);
185
186 /** size of data in the sending buffer */
187 public static final OptionUDT<Integer> UDT_SNDDATA = //
188 NEW(19, Integer.class, DECIMAL);
189 /** current consumed sending buffer utilization, read only, bytes */
190 public static final OptionUDT<Integer> Send_Buffer_Consumed = //
191 NEW(19, Integer.class, DECIMAL);
192
193 /** size of data available for recv */
194 public static final OptionUDT<Integer> UDT_RCVDATA = //
195 NEW(20, Integer.class, DECIMAL);
196 /** current available receiving buffer capacity, read only, bytes */
197 public static final OptionUDT<Integer> Receive_Buffer_Available = //
198 NEW(20, Integer.class, DECIMAL);
199
200 //
201
202 protected OptionUDT(final int code, final Class<T> klaz, final Format format) {
203
204 this.code = code;
205 this.type = klaz;
206 this.format = format;
207
208 values.add(this);
209
210 }
211
212 protected static <T> OptionUDT<T> NEW(final int code, final Class<T> klaz,
213 final Format format) {
214 return new OptionUDT<T>(code, klaz, format);
215 }
216
217 public static void appendSnapshot( //
218 final SocketUDT socketUDT, //
219 final StringBuilder text //
220 ) {
221
222 text.append("\n\t");
223 text.append(String.format("[id: 0x%08x]", socketUDT.id()));
224
225 for (final OptionUDT<?> option : values) {
226 int optionCode = 0;
227 String optionName = null;
228 String optionValue = null;
229 try {
230
231 optionCode = option.code;
232 optionName = option.name();
233
234 optionValue = option.format.convert(//
235 socketUDT.getOption(option));
236
237 if (optionName.startsWith("UD")) {
238 continue;
239 }
240
241 text.append("\n\t");
242 text.append(optionCode);
243 text.append(") ");
244 text.append(optionName);
245 text.append(" = ");
246 text.append(optionValue);
247
248 } catch (final Exception e) {
249 log.error("unexpected; " + optionName, e);
250 }
251
252 }
253
254 }
255
256 protected static final Logger log;
257 protected static final List<OptionUDT<?>> values;
258
259 private final int code;
260 private final Class<?> type;
261 private final Format format;
262 private String name;
263
264 public int code() {
265 return code;
266 }
267
268 public Class<?> type() {
269 return type;
270 }
271
272 public Format format() {
273 return format;
274 }
275
276 public String name() {
277 if (name == null) {
278 name = HelpUDT.constantFieldName(getClass(), this);
279 }
280 return name;
281 }
282
283 /**
284 * render options in human format
285 */
286 public enum Format {
287
288 DECIMAL() {
289 @Override
290 public String convert(final Object value) {
291 if (value instanceof Number) {
292 final long number = ((Number) value).longValue();
293 return String.format("%,d", number);
294 }
295 return "invalid format";
296 }
297 }, //
298
299 BINARY() {
300 @Override
301 public String convert(final Object value) {
302 if (value instanceof Number) {
303 final long number = ((Number) value).longValue();
304 return String.format("%,d (%,d K)", number, number / 1024);
305 }
306 return "invalid format";
307 }
308 }, //
309
310 BOOLEAN() {
311 @Override
312 public String convert(final Object value) {
313 if (value instanceof Boolean) {
314 final boolean bool = ((Boolean) value).booleanValue();
315 return String.format("%b", bool);
316 }
317 return "invalid format";
318 }
319 }, //
320
321 DEFAULT() {
322 @Override
323 public String convert(final Object value) {
324 return "" + value;
325 }
326 }, //
327
328 ;
329
330 public abstract String convert(Object value);
331
332 }
333
334 }