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    }