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 java.io.File;
011    import java.net.InetAddress;
012    import java.net.InetSocketAddress;
013    import java.nio.ByteBuffer;
014    import java.nio.IntBuffer;
015    import java.util.Set;
016    
017    import org.slf4j.Logger;
018    import org.slf4j.LoggerFactory;
019    
020    import com.barchart.udt.anno.Native;
021    import com.barchart.udt.lib.LibraryLoader;
022    import com.barchart.udt.nio.KindUDT;
023    import com.barchart.udt.util.HelpUDT;
024    
025    /**
026     * UDT native socket wrapper
027     * <p>
028     * note: current implementation supports IPv4 only (no IPv6)
029     */
030    public class SocketUDT {
031    
032            /**
033             * Maximum number of connections queued in listening mode by
034             * {@link #accept()}
035             */
036            public static final int DEFAULT_ACCEPT_QUEUE_SIZE = 256;
037    
038            /**
039             * Block size used by {@link #sendFile(File, long, long)}
040             */
041            public static final int DEFAULT_FILE_BLOCK_SIZE = 1 * 1024 * 1024;
042    
043            /**
044             * Maximum number sockets that can participate in a
045             * {@link com.barchart.udt.nio.SelectorUDT#select()} operation; see epoll.h
046             * to confirm current limit
047             */
048            public static final int DEFAULT_MAX_SELECTOR_SIZE = 1024;
049    
050            /**
051             * Minimum timeout of a {@link com.barchart.udt.nio.SelectorUDT#select()}
052             * operations.
053             */
054            public static final int DEFAULT_MIN_SELECTOR_TIMEOUT = 10;
055    
056            /**
057             * infinite message time to live;
058             */
059            public static final int INFINITE_TTL = -1;
060    
061            /**
062             * Helper value that can be checked from CCC class and force JNI library
063             * load
064             */
065            @Native
066            public static boolean INIT_OK = false;
067    
068            protected static final Logger log = LoggerFactory
069                            .getLogger(SocketUDT.class);
070    
071            /**
072             * JNI Signature that must match between java code and c++ code on all
073             * platforms; failure to match will abort native library load, as an
074             * indication of inconsistent build.
075             */
076            @Native
077            public static final int SIGNATURE_JNI = 20130512; // VersionUDT.BUILDTIME;
078    
079            /**
080             * infinite timeout:
081             * <p>
082             * blocking send/receive
083             * <p>
084             * epoll wait
085             */
086            public static final int TIMEOUT_INFINITE = -1;
087    
088            /**
089             * zero timeout:
090             * <p>
091             * epoll wait
092             */
093            public static long TIMEOUT_NONE = 0;
094    
095            /**
096             * UDT::select() sizeArray/sizeBuffer index offset for EXCEPTION report
097             */
098            @Native
099            public static final int UDT_EXCEPT_INDEX = 2;
100    
101            /**
102             * UDT::select() sizeArray/sizeBuffer index offset for READ interest
103             */
104            @Native
105            public static final int UDT_READ_INDEX = 0;
106    
107            /**
108             * UDT::select() sizeArray/sizeBuffer size count or number of arrays/buffers
109             */
110            @Native
111            public static final int UDT_SIZE_COUNT = 3;
112    
113            /**
114             * UDT::select() sizeArray/sizeBuffer index offset for WRITE interest
115             */
116            @Native
117            public static final int UDT_WRITE_INDEX = 1;
118    
119            /**
120             * Native library loader.
121             * 
122             * @throws RuntimeException
123             */
124            static {
125    
126                    try {
127    
128                            final String location = ResourceUDT.getLibraryExtractLocation();
129    
130                            log.info("library location : {}", location);
131    
132                            final String loaderName = ResourceUDT.getLibraryLoaderClassName();
133    
134                            log.info("loader provider  : {}", loaderName);
135    
136                            @SuppressWarnings("unchecked")
137                            final Class<LibraryLoader> loaderClass = //
138                            (Class<LibraryLoader>) Class.forName(loaderName);
139    
140                            final LibraryLoader loaderInstance = loaderClass.newInstance();
141    
142                            loaderInstance.load(location);
143    
144                    } catch (final Throwable e) {
145                            log.error("Failed to LOAD native library", e);
146                            throw new RuntimeException("load", e);
147                    }
148    
149                    try {
150                            initClass0();
151                    } catch (final Throwable e) {
152                            log.error("Failed to INIT native library", e);
153                            throw new RuntimeException("init", e);
154                    }
155    
156                    if (SIGNATURE_JNI != getSignatureJNI0()) {
157                            log.error("Java/Native SIGNATURE inconsistent");
158                            throw new RuntimeException("signature");
159                    }
160    
161                    INIT_OK = true;
162    
163                    log.debug("native library load & init OK");
164    
165            }
166    
167            /**
168             * Cleans up global JNI references and the UDT library.
169             * <p>
170             * The behavior of SocketUDT class after a call to cleanup is undefined, so
171             * it should only ever be called once you are done and you are ready for the
172             * class loader to unload the JNI library
173             * 
174             * @throws ExceptionUDT
175             */
176            public static void cleanup() throws ExceptionUDT {
177                    stopClass0();
178            }
179    
180            /**
181             * @see <a
182             *      href="http://udt.sourceforge.net/udt4/doc/epoll.htm">UDT::epoll_add_usock()</a>
183             */
184            protected static native void epollAdd0( //
185                            final int epollID, //
186                            final int socketID, //
187                            final int epollOpt //
188            ) throws ExceptionUDT;
189    
190            /**
191             * @return epoll id
192             * 
193             * @see <a
194             *      href="http://udt.sourceforge.net/udt4/doc/epoll.htm">UDT::epoll_create()</a>
195             */
196            protected static native int epollCreate0() throws ExceptionUDT;
197    
198            /**
199             * @see <a
200             *      href="http://udt.sourceforge.net/udt4/doc/epoll.htm">UDT::epoll_release()</a>
201             */
202            protected static native void epollRelease0(final int epollID)
203                            throws ExceptionUDT;
204    
205            /**
206             * @see <a
207             *      href="http://udt.sourceforge.net/udt4/doc/epoll.htm">UDT::epoll_remove_usock()</a>
208             */
209            protected static native void epollRemove0( //
210                            final int epollID, final int socketID) throws ExceptionUDT;
211    
212            /**
213             * update epoll mask
214             */
215            protected static native void epollUpdate0(int epollID, int socketID,
216                            int epollMask) throws ExceptionUDT;
217    
218            /**
219             * query epoll mask
220             */
221            protected static native int epollVerify0(int epollID, int socketID)
222                            throws ExceptionUDT;
223    
224            /**
225             * @see <a
226             *      href="http://udt.sourceforge.net/udt4/doc/epoll.htm">UDT::epoll_wait()</a>
227             */
228            protected static native int epollWait0( //
229                            final int epollID, //
230                            final IntBuffer readBuffer, //
231                            final IntBuffer writeBuffer, //
232                            final IntBuffer sizeBuffer, //
233                            final long millisTimeout) throws ExceptionUDT;
234    
235            /**
236             * Verify that java code and c++ code builds are consistent.
237             * 
238             * @see #SIGNATURE_JNI
239             */
240            protected static native int getSignatureJNI0();
241    
242            /**
243             * Call this after loading native library.
244             * 
245             * @see <a
246             *      href="http://udt.sourceforge.net/udt4/doc/startup.htm">UDT::startup()</a>
247             */
248            protected static native void initClass0() throws ExceptionUDT;
249    
250            /**
251             * receive into a complete byte array
252             * 
253             * @see <a
254             *      href="http://udt.sourceforge.net/udt4/doc/recv.htm">UDT::recv()</a>
255             * @see <a
256             *      href="http://udt.sourceforge.net/udt4/doc/recv.htm">UDT::recvmsg()</a>
257             */
258            protected static native int receive0(//
259                            final int socketID, //
260                            final int socketType, //
261                            final byte[] array //
262            ) throws ExceptionUDT;
263    
264            /**
265             * receive into a portion of a byte array
266             * 
267             * @see <a
268             *      href="http://udt.sourceforge.net/udt4/doc/recv.htm">UDT::recv()</a>
269             * @see <a
270             *      href="http://udt.sourceforge.net/udt4/doc/recv.htm">UDT::recvmsg()</a>
271             */
272            protected static native int receive1( //
273                            final int socketID, //
274                            final int socketType, //
275                            final byte[] array, //
276                            final int position, //
277                            final int limit //
278            ) throws ExceptionUDT;
279    
280            /**
281             * receive into a {@link java.nio.channels.DirectByteBuffer}
282             * 
283             * @see <a
284             *      href="http://udt.sourceforge.net/udt4/doc/recv.htm">UDT::recv()</a>
285             * @see <a
286             *      href="http://udt.sourceforge.net/udt4/doc/recv.htm">UDT::recvmsg()</a>
287             */
288            protected static native int receive2( //
289                            final int socketID, //
290                            final int socketType, //
291                            final ByteBuffer buffer, //
292                            final int position, //
293                            final int limit //
294            ) throws ExceptionUDT;
295    
296            /**
297             * Receive file.
298             * 
299             * @see <a
300             *      href="http://udt.sourceforge.net/udt4/doc/sendfile.htm">UDT::recvfile</a>
301             */
302            protected static native long receiveFile0( //
303                            final int socketID, //
304                            final String path, //
305                            long offset, //
306                            long length, //
307                            int block //
308            ) throws ExceptionUDT;
309    
310            /**
311             * Basic access to UDT socket readiness selection feature. Based on
312             * {@link java.nio.DirectIntBuffer} info exchange.Timeout is in
313             * milliseconds.
314             * 
315             * @param millisTimeout
316             * 
317             *            http://udt.sourceforge.net/udt4/doc/epoll.htm
318             * 
319             *            "Finally, for epoll_wait, negative timeout value will make the
320             *            function to wait until an event happens. If the timeout value
321             *            is 0, then the function returns immediately with any sockets
322             *            associated an IO event. If timeout occurs before any event
323             *            happens, the function returns 0".
324             * 
325             * 
326             * @return <code><0</code> : should not happen<br>
327             *         <code>=0</code> : timeout, no ready sockets<br>
328             *         <code>>0</code> : total number or reads, writes, exceptions<br>
329             * 
330             * @see #epollWait0(int, IntBuffer, IntBuffer, IntBuffer, long)
331             */
332            public static int selectEpoll( //
333                            final int epollId, //
334                            final IntBuffer readBuffer, //
335                            final IntBuffer writeBuffer, //
336                            final IntBuffer sizeBuffer, //
337                            final long millisTimeout) throws ExceptionUDT {
338    
339                    /** asserts are contracts */
340    
341                    assert readBuffer != null && readBuffer.isDirect();
342                    assert writeBuffer != null && writeBuffer.isDirect();
343                    assert sizeBuffer != null && sizeBuffer.isDirect();
344    
345                    return epollWait0( //
346                                    epollId, //
347                                    readBuffer, //
348                                    writeBuffer, //
349                                    sizeBuffer, //
350                                    millisTimeout //
351                    );
352    
353            }
354    
355            /**
356             * send from a complete byte[] array;
357             * 
358             * wrapper for <em>UDT::send()</em>, <em>UDT::sendmsg()</em>
359             * 
360             * @see <a
361             *      href="http://udt.sourceforge.net/udt4/doc/send.htm">UDT::send()</a>
362             * @see <a
363             *      href="http://udt.sourceforge.net/udt4/doc/sendmsg.htm">UDT::sendmsg()</a>
364             */
365            protected static native int send0( //
366                            final int socketID, //
367                            final int socketType, //
368                            final int timeToLive, //
369                            final boolean isOrdered, //
370                            final byte[] array //
371            ) throws ExceptionUDT;
372    
373            /**
374             * send from a portion of a byte[] array;
375             * 
376             * wrapper for <em>UDT::send()</em>, <em>UDT::sendmsg()</em>
377             * 
378             * @see <a
379             *      href="http://udt.sourceforge.net/udt4/doc/send.htm">UDT::send()</a>
380             * @see <a
381             *      href="http://udt.sourceforge.net/udt4/doc/sendmsg.htm">UDT::sendmsg()</a>
382             */
383            protected static native int send1( //
384                            final int socketID, //
385                            final int socketType, //
386                            final int timeToLive, //
387                            final boolean isOrdered, //
388                            final byte[] array, // /
389                            final int arayPosition, //
390                            final int arrayLimit //
391            ) throws ExceptionUDT;
392    
393            /**
394             * send from {@link java.nio.DirectByteBuffer};
395             * 
396             * wrapper for <em>UDT::send()</em>, <em>UDT::sendmsg()</em>
397             * 
398             * @see <a
399             *      href="http://udt.sourceforge.net/udt4/doc/send.htm">UDT::send()</a>
400             * @see <a
401             *      href="http://udt.sourceforge.net/udt4/doc/sendmsg.htm">UDT::sendmsg()</a>
402             */
403            protected static native int send2( //
404                            final int socketID, //
405                            final int socketType, //
406                            final int timeToLive, //
407                            final boolean isOrdered, //
408                            final ByteBuffer buffer, //
409                            final int bufferPosition, //
410                            final int bufferLimit //
411            ) throws ExceptionUDT;
412    
413            /**
414             * Send file.
415             * 
416             * @see <a
417             *      href="http://udt.sourceforge.net/udt4/doc/sendfile.htm">UDT::sendfile</a>
418             */
419            protected static native long sendFile0( //
420                            final int socketID, //
421                            final String path, //
422                            long offset, //
423                            long length, //
424                            int block //
425            ) throws ExceptionUDT;
426    
427            /**
428             * Call this before unloading native library.
429             * 
430             * @see <a
431             *      href="http://udt.sourceforge.net/udt4/doc/cleanup.htm.htm">UDT::cleanup()</a>
432             */
433            protected static native void stopClass0() throws ExceptionUDT;
434    
435            // ###########################################
436            // ### used for development & testing only
437            // ###
438    
439            protected static native void testCrashJVM0();
440    
441            protected static native void testDirectByteBufferAccess0(ByteBuffer buffer);
442    
443            protected static native void testDirectIntBufferAccess0(IntBuffer buffer);
444    
445            protected static native void testDirectIntBufferLoad0(IntBuffer buffer);
446    
447            protected static native void testEmptyCall0();
448    
449            protected static native void testFillArray0(byte[] array);
450    
451            protected static native void testFillBuffer0(ByteBuffer buffer);
452    
453            protected static native void testGetSetArray0(int[] array, boolean isReturn);
454    
455            protected static native void testInvalidClose0(int socketID)
456                            throws ExceptionUDT;
457    
458            protected static native void testIterateArray0(Object[] array);
459    
460            protected static native void testIterateSet0(Set<Object> set);
461    
462            protected static native int[] testMakeArray0(int size);
463    
464            // ###
465            // ### used for development & testing only
466            // ###########################################
467    
468            /**
469             * java copy of underlying native accept queue size parameter
470             * 
471             * @see #listen(int)
472             * @see #accept()
473             */
474            private volatile int listenQueueSize;
475    
476            /**
477             * local end point; loaded by JNI by {@link #hasLoadedLocalSocketAddress()}
478             */
479            @Native
480            private volatile InetSocketAddress localSocketAddress;
481    
482            /**
483             */
484            private volatile boolean messageIsOrdered;
485    
486            /**
487             */
488            private volatile int messageTimeTolive;
489    
490            /**
491             */
492            @Native
493            private final MonitorUDT monitor;
494    
495            /**
496             * remote end point; loaded by JNI by
497             * {@link #hasLoadedRemoteSocketAddress()}
498             */
499            @Native
500            private volatile InetSocketAddress remoteSocketAddress;
501    
502            /**
503             * native address family; read by JNI
504             * <p>
505             * TODO add support for AF_INET6
506             */
507            @Native
508            private final int socketAddressFamily;
509    
510            /**
511             * native descriptor; read by JNI; see udt.h "typedef int UDTSOCKET;"
512             */
513            @Native
514            private final int socketID;
515    
516            /**
517             */
518            @Native
519            private final TypeUDT type;
520    
521            /**
522             * "Primary" socket. Default constructor; will apply
523             * {@link #setDefaultMessageSendMode()}
524             * 
525             * @param type
526             *            UDT socket type
527             */
528            public SocketUDT(final TypeUDT type) throws ExceptionUDT {
529                    synchronized (SocketUDT.class) {
530                            this.type = type;
531                            this.monitor = new MonitorUDT(this);
532                            this.socketID = initInstance0(type.code);
533                            this.socketAddressFamily = 2; // ipv4
534                            setDefaultMessageSendMode();
535                    }
536                    log.debug("init : {}", this);
537            }
538    
539            /**
540             * "Secondary" socket. Made by {@link #accept0()}, will apply
541             * {@link #setDefaultMessageSendMode()}
542             * 
543             * @param socketID
544             *            UDT socket descriptor;
545             */
546            protected SocketUDT(final TypeUDT type, final int socketID)
547                            throws ExceptionUDT {
548                    synchronized (SocketUDT.class) {
549                            this.type = type;
550                            this.monitor = new MonitorUDT(this);
551                            this.socketID = initInstance1(socketID);
552                            this.socketAddressFamily = 2; // ipv4
553                            setDefaultMessageSendMode();
554                    }
555                    log.debug("init : {}", this);
556            }
557    
558            /**
559             * @return null : no incoming connections (non-blocking mode only)<br>
560             *         non null : newly accepted SocketUDT (both blocking and
561             *         non-blocking)<br>
562             */
563            public SocketUDT accept() throws ExceptionUDT {
564                    return accept0();
565            }
566    
567            /**
568             * @see <a
569             *      href="http://udt.sourceforge.net/udt4/doc/accept.htm">UDT::accept()</a>
570             */
571            protected native SocketUDT accept0() throws ExceptionUDT;
572    
573            public void bind(final InetSocketAddress localSocketAddress) //
574                            throws ExceptionUDT, IllegalArgumentException {
575                    HelpUDT.checkSocketAddress(localSocketAddress);
576                    bind0(localSocketAddress);
577            }
578    
579            /**
580             * @see <a
581             *      href="http://udt.sourceforge.net/udt4/doc/bind.htm">UDT::bind()</a>
582             */
583            protected native void bind0(final InetSocketAddress localSocketAddress)
584                            throws ExceptionUDT;
585    
586            /**
587             * Clear error status on a socket, if any.
588             * 
589             * @see <a href="http://udt.sourceforge.net/udt4/doc/t-error.htm">UDT Error
590             *      Handling</a>
591             */
592            public void clearError() {
593                    clearError0();
594            }
595    
596            /**
597             * @see <a href="http://udt.sourceforge.net/udt4/doc/t-error.htm">UDT Error
598             *      Handling</a>
599             */
600            protected native void clearError0();
601    
602            /**
603             * Close socket if not already closed.
604             * 
605             * @see #close0()
606             */
607            public void close() throws ExceptionUDT {
608                    synchronized (SocketUDT.class) {
609                            switch (status()) {
610                            case INIT:
611                            case OPENED:
612                            case LISTENING:
613                            case CONNECTING:
614                            case CONNECTED:
615                            case BROKEN:
616                                    /** Requires close. */
617                                    close0();
618                                    log.debug("done : {}", this);
619                                    break;
620                            case CLOSING:
621                            case CLOSED:
622                            case NONEXIST:
623                                    /** Effectively closed. */
624                                    log.debug("dead : {}", this);
625                                    break;
626                            default:
627                                    log.error("Invalid socket/status {}/{}", this, status());
628                            }
629                    }
630            }
631    
632            /**
633             * @see <a
634             *      href="http://udt.sourceforge.net/udt4/doc/close.htm">UDT::close()</a>
635             */
636            protected native void close0() throws ExceptionUDT;
637    
638            /**
639             * Connect to remote UDT socket.
640             * <p>
641             * Can be blocking or non blocking call; depending on
642             * {@link OptionUDT#Is_Receive_Synchronous}
643             * <p>
644             * Timing: UDT uses hard coded connect timeout:
645             * <p>
646             * normal socket: 3 seconds
647             * <p>
648             * rendezvous socket: 30 seconds; when
649             * {@link OptionUDT#Is_Randezvous_Connect_Enabled} is true
650             * 
651             * @see #connect0(InetSocketAddress)
652             */
653            public void connect(final InetSocketAddress remoteSocketAddress) //
654                            throws ExceptionUDT {
655                    HelpUDT.checkSocketAddress(remoteSocketAddress);
656                    connect0(remoteSocketAddress);
657            }
658    
659            /**
660             * @see <a
661             *      href="http://udt.sourceforge.net/udt4/doc/connect.htm">UDT::connect()</a>
662             */
663            protected native void connect0(final InetSocketAddress remoteSocketAddress)
664                            throws ExceptionUDT;
665    
666            /**
667             * Note: equality is based on {@link #socketID}.
668             */
669            @Override
670            public boolean equals(final Object otherSocketUDT) {
671                    if (otherSocketUDT instanceof SocketUDT) {
672                            final SocketUDT other = (SocketUDT) otherSocketUDT;
673                            return other.socketID == this.socketID;
674                    }
675                    return false;
676            }
677    
678            /**
679             * NOTE: catch all exceptions; else prevents GC
680             * <p>
681             * NOTE: do not leak "this" references; else prevents GC
682             */
683            @Override
684            protected void finalize() {
685                    try {
686                            close();
687                            super.finalize();
688                    } catch (final Throwable e) {
689                            log.error("failed to close id=" + socketID, e);
690                    }
691            }
692    
693            /**
694             * Error object wrapper.
695             * 
696             * @return error status set by last socket operation
697             **/
698            public ErrorUDT getError() {
699                    final int code = getErrorCode();
700                    return ErrorUDT.errorFrom(code);
701            }
702    
703            /**
704             * Error code set by last operation on a socket.
705             * 
706             * @see <a href="http://udt.sourceforge.net/udt4/doc/t-error.htm">UDT Error
707             *      Handling</a>
708             */
709            public int getErrorCode() {
710                    return getErrorCode0();
711            }
712    
713            /**
714             * @see <a href="http://udt.sourceforge.net/udt4/doc/t-error.htm">UDT Error
715             *      Handling</a>
716             */
717            protected native int getErrorCode0();
718    
719            /**
720             * Native error message set by last operation on a socket.
721             * 
722             * @see <a
723             *      href="http://udt.sourceforge.net/udt4/doc/t-error.htm">t-error.htm</a>
724             */
725            public String getErrorMessage() {
726                    return getErrorMessage0();
727            }
728    
729            /**
730             * @see <a href="http://udt.sourceforge.net/udt4/doc/t-error.htm">UDT Error
731             *      Handling</a>
732             */
733            protected native String getErrorMessage0();
734    
735            /**
736             * @see #listen(int)
737             */
738            public int getListenQueueSize() {
739                    return listenQueueSize;
740            }
741    
742            /**
743             * @return null : not bound<br>
744             *         not null : valid address; result of
745             *         {@link #bind(InetSocketAddress)}<br>
746             */
747            public InetAddress getLocalInetAddress() {
748                    try {
749                            final InetSocketAddress local = getLocalSocketAddress();
750                            if (local == null) {
751                                    return null;
752                            } else {
753                                    return local.getAddress();
754                            }
755                    } catch (final Exception e) {
756                            log.debug("failed to get local address", e);
757                            return null;
758                    }
759            }
760    
761            /**
762             * @return 0 : not bound<br>
763             *         >0 : valid port; result of {@link #bind(InetSocketAddress)}<br>
764             */
765            public int getLocalInetPort() {
766                    try {
767                            final InetSocketAddress local = getLocalSocketAddress();
768                            if (local == null) {
769                                    return 0;
770                            } else {
771                                    return local.getPort();
772                            }
773                    } catch (final Exception e) {
774                            log.debug("failed to get local port", e);
775                            return 0;
776                    }
777            }
778    
779            /**
780             * @return null: not bound; <br>
781             *         not null: local UDT socket address to which the the socket is
782             *         bound<br>
783             * @see #hasLoadedLocalSocketAddress()
784             */
785            public InetSocketAddress getLocalSocketAddress() throws ExceptionUDT {
786                    if (hasLoadedLocalSocketAddress()) {
787                            return localSocketAddress;
788                    } else {
789                            return null;
790                    }
791            }
792    
793            /**
794             * default isOrdered value used by sendmsg mode
795             * 
796             * @see <a
797             *      href="http://udt.sourceforge.net/udt4/doc/sendmsg.htm">UDT::sendmsg()</a>
798             */
799            public boolean getMessageIsOdered() {
800                    return messageIsOrdered;
801            }
802    
803            /**
804             * default timeToLive value used by sendmsg mode
805             * 
806             * @see <a
807             *      href="http://udt.sourceforge.net/udt4/doc/sendmsg.htm">UDT::sendmsg()</a>
808             */
809            public int getMessageTimeTolLive() {
810                    return messageTimeTolive;
811            }
812    
813            /**
814             * @see #getOption0(int, Class)
815             */
816            @SuppressWarnings("unchecked")
817            public <T> T getOption(final OptionUDT<T> option) throws ExceptionUDT {
818    
819                    if (option == null) {
820                            throw new IllegalArgumentException("option == null");
821                    }
822    
823                    return (T) getOption0(option.code(), option.type());
824    
825            }
826    
827            /**
828             * @see <a
829             *      href="http://udt.sourceforge.net/udt4/doc/opt.htm">UDT::getsockopt()</a>
830             */
831            protected native Object getOption0(final int code, final Class<?> klaz)
832                            throws ExceptionUDT;
833    
834            /**
835             * Get maximum receive buffer size. Reflects minimum of protocol-level (UDT)
836             * and kernel-level(UDP) settings.
837             * 
838             * @see java.net.Socket#getReceiveBufferSize()
839             */
840            public int getReceiveBufferSize() throws ExceptionUDT {
841                    final int protocolSize = getOption(OptionUDT.Protocol_Receive_Buffer_Size);
842                    final int kernelSize = getOption(OptionUDT.System_Receive_Buffer_Size);
843                    return Math.min(protocolSize, kernelSize);
844            }
845    
846            //
847    
848            /**
849             * @return null : not connected<br>
850             *         not null : valid address; result of
851             *         {@link #connect(InetSocketAddress)}<br>
852             */
853            public InetAddress getRemoteInetAddress() {
854                    try {
855                            final InetSocketAddress remote = getRemoteSocketAddress();
856                            if (remote == null) {
857                                    return null;
858                            } else {
859                                    return remote.getAddress();
860                            }
861                    } catch (final Exception e) {
862                            log.debug("failed to get remote address", e);
863                            return null;
864                    }
865            }
866    
867            /**
868             * @return 0 : not connected<br>
869             *         >0 : valid port ; result of {@link #connect(InetSocketAddress)}<br>
870             */
871            public int getRemoteInetPort() {
872                    try {
873                            final InetSocketAddress remote = getRemoteSocketAddress();
874                            if (remote == null) {
875                                    return 0;
876                            } else {
877                                    return remote.getPort();
878                            }
879                    } catch (final Exception e) {
880                            log.debug("failed to get remote port", e);
881                            return 0;
882                    }
883            }
884    
885            /**
886             * @return null : not connected; <br>
887             *         not null: remote UDT peer socket address to which this socket is
888             *         connected <br>
889             * @see #hasLoadedRemoteSocketAddress()
890             */
891            public InetSocketAddress getRemoteSocketAddress() throws ExceptionUDT {
892                    if (hasLoadedRemoteSocketAddress()) {
893                            return remoteSocketAddress;
894                    } else {
895                            return null;
896                    }
897            }
898    
899            /**
900             * Check if local bind address is set to reuse mode.
901             * 
902             * @see java.net.Socket#getReuseAddress()
903             */
904            public boolean getReuseAddress() throws ExceptionUDT {
905                    return getOption(OptionUDT.Is_Address_Reuse_Enabled);
906            }
907    
908            /**
909             * Get maximum send buffer size. Reflects minimum of protocol-level (UDT)
910             * and kernel-level(UDP) settings.
911             * 
912             * @see java.net.Socket#getSendBufferSize()
913             */
914            public int getSendBufferSize() throws ExceptionUDT {
915                    final int protocolSize = getOption(OptionUDT.Protocol_Send_Buffer_Size);
916                    final int kernelSize = getOption(OptionUDT.System_Send_Buffer_Size);
917                    return Math.min(protocolSize, kernelSize);
918            }
919    
920            /**
921             * Get time to linger on close (seconds).
922             * 
923             * @see java.net.Socket#getSoLinger()
924             */
925            public int getSoLinger() throws ExceptionUDT {
926                    return getOption(OptionUDT.Time_To_Linger_On_Close).intValue();
927            }
928    
929            /**
930             * Get "any blocking operation" timeout setting.
931             * 
932             * Returns milliseconds; zero return means "infinite"; negative means
933             * invalid
934             * 
935             * @see java.net.Socket#getSoTimeout()
936             */
937            public int getSoTimeout() throws ExceptionUDT {
938                    final int sendTimeout = getOption(OptionUDT.Send_Timeout);
939                    final int receiveTimeout = getOption(OptionUDT.Receive_Timeout);
940                    final int millisTimeout;
941                    if (sendTimeout != receiveTimeout) {
942                            log.error("sendTimeout != receiveTimeout");
943                            millisTimeout = Math.max(sendTimeout, receiveTimeout);
944                    } else {
945                            // map from UDT value convention to java.net.Socket value convention
946                            if (sendTimeout < 0) {
947                                    // UDT infinite
948                                    millisTimeout = 0;
949                            } else if (sendTimeout > 0) {
950                                    // UDT finite
951                                    millisTimeout = sendTimeout;
952                            } else { // ==0
953                                    log.error("UDT reported unexpected zero timeout");
954                                    millisTimeout = -1;
955                            }
956                    }
957                    return millisTimeout;
958            }
959    
960            /**
961             * @see <a href="http://udt.sourceforge.net/udt4/doc/socket.htm"></a>
962             */
963            protected native int getStatus0();
964    
965            //
966    
967            /**
968             * Note: uses {@link #socketID} as hash code.
969             */
970            @Override
971            public int hashCode() {
972                    return socketID;
973            }
974    
975            /**
976             * Load {@link #localSocketAddress} value.
977             * 
978             * @see <a
979             *      href="http://udt.sourceforge.net/udt4/doc/sockname.htm">UDT::sockname()</a>
980             */
981            protected native boolean hasLoadedLocalSocketAddress();
982    
983            /**
984             * Load {@link #remoteSocketAddress} value.
985             * 
986             * @see <a
987             *      href="http://udt.sourceforge.net/udt4/doc/peername.htm">UDT::peername()</a>
988             */
989            protected native boolean hasLoadedRemoteSocketAddress();
990    
991            /**
992             * native socket descriptor id; assigned by udt library
993             */
994            public int id() {
995                    return socketID;
996            }
997    
998            /**
999             * used by default constructor
1000             */
1001            protected native int initInstance0(int typeCode) throws ExceptionUDT;
1002    
1003            /**
1004             * used by accept() internally
1005             */
1006            protected native int initInstance1(int socketUDT) throws ExceptionUDT;
1007    
1008            /**
1009             * Check if socket is in strict blocking mode. (JDK semantics)
1010             * 
1011             * @return true : socket is valid and both send and receive are set to
1012             *         blocking mode; false : at least one channel is set to
1013             *         non-blocking mode or socket is invalid;
1014             * 
1015             * @see #isNonBlocking()
1016             * @see #setBlocking(boolean)
1017             */
1018            public boolean isBlocking() {
1019                    try {
1020                            if (isOpen()) {
1021                                    final boolean isReceiveBlocking = getOption(OptionUDT.Is_Receive_Synchronous);
1022                                    final boolean isSendBlocking = getOption(OptionUDT.Is_Send_Synchronous);
1023                                    return isReceiveBlocking && isSendBlocking;
1024                            }
1025                    } catch (final Exception e) {
1026                            log.error("failed to get option", e);
1027                    }
1028                    return false;
1029            }
1030    
1031            /**
1032             * Check if socket is bound. (JDK semantics)
1033             * 
1034             * @return true : {@link #bind(InetSocketAddress)} was successful<br>
1035             *         false : otherwise<br>
1036             */
1037            public boolean isBound() {
1038                    switch (status()) {
1039                    case OPENED:
1040                    case CONNECTING:
1041                    case CONNECTED:
1042                    case LISTENING:
1043                            return true;
1044                    default:
1045                            return false;
1046                    }
1047            }
1048    
1049            /**
1050             * Check if socket is closed. A convenience !isOpen();
1051             * 
1052             * @see #isOpen()
1053             */
1054            public boolean isClosed() {
1055                    return !isOpen();
1056            }
1057    
1058            /**
1059             * Check if {@link KindUDT#CONNECTOR} socket is connected. (JDK semantics)
1060             * 
1061             * @return true : {@link #connect(InetSocketAddress)} was successful<br>
1062             *         false : otherwise<br>
1063             */
1064            public boolean isConnected() {
1065                    switch (status()) {
1066                    case CONNECTED:
1067                            return true;
1068                    default:
1069                            return false;
1070                    }
1071            }
1072    
1073            /**
1074             * Check if socket is in strict non-blocking mode.
1075             * 
1076             * @return true : socket is valid and both send and receive are set to NON
1077             *         blocking mode; false : at least one channel is set to blocking
1078             *         mode or socket is invalid;
1079             * @see #isBlocking()
1080             * @see #setBlocking(boolean)
1081             */
1082            public boolean isNonBlocking() {
1083                    try {
1084                            if (isOpen()) {
1085                                    final boolean isReceiveBlocking = getOption(OptionUDT.Is_Receive_Synchronous);
1086                                    final boolean isSendBlocking = getOption(OptionUDT.Is_Send_Synchronous);
1087                                    return !isReceiveBlocking && !isSendBlocking;
1088                            }
1089                    } catch (final Exception e) {
1090                            log.error("failed to get option", e);
1091                    }
1092                    return false;
1093            }
1094    
1095            /**
1096             * Check if socket is open. (JDK semantics). The status of underlying UDT
1097             * socket is mapped into JDK expected categories
1098             * 
1099             * @see StatusUDT
1100             */
1101            public boolean isOpen() {
1102                    switch (status()) {
1103                    case INIT:
1104                    case OPENED:
1105                    case LISTENING:
1106                    case CONNECTING:
1107                    case CONNECTED:
1108                            return true;
1109                    default:
1110                            return false;
1111                    }
1112            }
1113    
1114            public boolean isRendezvous() {
1115                    try {
1116                            if (isOpen()) {
1117                                    return getOption(OptionUDT.Is_Randezvous_Connect_Enabled);
1118                            }
1119                    } catch (final Exception e) {
1120                            log.error("failed to get option", e);
1121                    }
1122                    return false;
1123            }
1124    
1125            /**
1126             * @param queueSize
1127             *            maximum number of queued clients
1128             * 
1129             * @see #listen0(int)
1130             */
1131            public void listen(final int queueSize) throws ExceptionUDT {
1132                    if (queueSize <= 0) {
1133                            throw new IllegalArgumentException("queueSize <= 0");
1134                    }
1135                    listenQueueSize = queueSize;
1136                    listen0(queueSize);
1137            }
1138    
1139            /**
1140             * @see <a
1141             *      href="http://udt.sourceforge.net/udt4/doc/listen.htm">UDT::listen()</a>
1142             */
1143            protected native void listen0(final int queueSize) throws ExceptionUDT;
1144    
1145            /**
1146             * performance monitor; updated by {@link #updateMonitor(boolean)} in JNI
1147             * 
1148             * @see #updateMonitor(boolean)
1149             */
1150            public MonitorUDT monitor() {
1151                    return monitor;
1152            }
1153    
1154            /**
1155             * receive into byte[] array upto <code>array.length</code> bytes
1156             * 
1157             * @return <code>-1</code> : nothing received (non-blocking only)<br>
1158             *         <code>=0</code> : timeout expired (blocking only)<br>
1159             *         <code>>0</code> : normal receive, byte count<br>
1160             * @see #receive0(int, int, byte[])
1161             */
1162            public int receive(final byte[] array) throws ExceptionUDT {
1163    
1164                    HelpUDT.checkArray(array);
1165    
1166                    return receive0(socketID, type.code, array);
1167    
1168            }
1169    
1170            /**
1171             * receive into byte[] array upto <code>size=limit-position</code> bytes
1172             * 
1173             * @return <code>-1</code> : nothing received (non-blocking only)<br>
1174             *         <code>=0</code> : timeout expired (blocking only)<br>
1175             *         <code>>0</code> : normal receive, byte count<br>
1176             * @see #receive1(int, int, byte[], int, int)
1177             */
1178            public int receive(final byte[] array, final int position, final int limit)
1179                            throws ExceptionUDT {
1180    
1181                    HelpUDT.checkArray(array);
1182    
1183                    return receive1(socketID, type.code, array, position, limit);
1184    
1185            }
1186    
1187            /**
1188             * receive into {@link java.nio.channels.DirectByteBuffer}; upto
1189             * {@link java.nio.ByteBuffer#remaining()} bytes
1190             * 
1191             * @return <code>-1</code> : nothing received (non-blocking only)<br>
1192             *         <code>=0</code> : timeout expired (blocking only)<br>
1193             *         <code>>0</code> : normal receive, byte count<br>
1194             * @see #receive2(int, int, ByteBuffer, int, int)
1195             */
1196            public int receive(final ByteBuffer buffer) throws ExceptionUDT {
1197    
1198                    HelpUDT.checkBuffer(buffer);
1199    
1200                    final int position = buffer.position();
1201                    final int limit = buffer.limit();
1202                    final int remaining = buffer.remaining();
1203    
1204                    final int sizeReceived = //
1205                    receive2(socketID, type.code, buffer, position, limit);
1206    
1207                    if (sizeReceived <= 0) {
1208                            return sizeReceived;
1209                    }
1210    
1211                    if (sizeReceived <= remaining) {
1212                            buffer.position(position + sizeReceived);
1213                            return sizeReceived;
1214                    } else { // should not happen
1215                            log.error("sizeReceived > remaining");
1216                            return 0;
1217                    }
1218    
1219            }
1220    
1221            //
1222    
1223            /**
1224             * Receive file from remote peer.
1225             * 
1226             * @see #receiveFile0(int, String, long, long, int)
1227             */
1228            public long receiveFile( //
1229                            final File file, //
1230                            final long offset, //
1231                            final long length//
1232            ) throws ExceptionUDT {
1233    
1234                    if (type == TypeUDT.DATAGRAM) {
1235                            throw new IllegalStateException("invalid socket type : " + type);
1236                    }
1237    
1238                    if (file == null || !file.exists() || !file.isFile()
1239                                    || !file.canWrite()) {
1240                            throw new IllegalArgumentException("invalid file : " + file);
1241                    }
1242    
1243                    if (offset < 0 || offset > file.length()) {
1244                            throw new IllegalArgumentException("invalid offset : " + offset);
1245                    }
1246    
1247                    if (length < 0 || offset + length > file.length()) {
1248                            throw new IllegalArgumentException("invalid length : " + length);
1249                    }
1250    
1251                    final String path = file.getAbsolutePath();
1252    
1253                    final int block;
1254                    if (length > DEFAULT_FILE_BLOCK_SIZE) {
1255                            block = DEFAULT_FILE_BLOCK_SIZE;
1256                    } else {
1257                            block = (int) length;
1258                    }
1259    
1260                    return receiveFile0(id(), path, offset, length, block);
1261    
1262            }
1263    
1264            /**
1265             * send from byte[] array upto <code>size=array.length</code> bytes
1266             * 
1267             * @param array
1268             *            array to send
1269             * @return <code>-1</code> : no buffer space (non-blocking only) <br>
1270             *         <code>=0</code> : timeout expired (blocking only) <br>
1271             *         <code>>0</code> : normal send, actual sent byte count <br>
1272             * @see #send0(int, int, int, boolean, byte[])
1273             */
1274            public int send(final byte[] array) throws ExceptionUDT {
1275    
1276                    HelpUDT.checkArray(array);
1277    
1278                    return send0( //
1279                                    socketID, //
1280                                    type.code, //
1281                                    messageTimeTolive, //
1282                                    messageIsOrdered, //
1283                                    array //
1284                    );
1285    
1286            }
1287    
1288            /**
1289             * send from byte[] array upto <code>size=limit-position</code> bytes
1290             * 
1291             * @param array
1292             *            array to send
1293             * @param position
1294             *            start of array portion to send
1295             * @param limit
1296             *            finish of array portion to send
1297             * @return <code>-1</code> : no buffer space (non-blocking only) <br>
1298             *         <code>=0</code> : timeout expired (blocking only) <br>
1299             *         <code>>0</code> : normal send, actual sent byte count <br>
1300             * @see #send1(int, int, int, boolean, byte[], int, int)
1301             */
1302            public int send( //
1303                            final byte[] array, //
1304                            final int position, //
1305                            final int limit //
1306            ) throws ExceptionUDT {
1307    
1308                    HelpUDT.checkArray(array);
1309    
1310                    return send1( //
1311                                    socketID, //
1312                                    type.code, //
1313                                    messageTimeTolive, //
1314                                    messageIsOrdered, //
1315                                    array, //
1316                                    position, //
1317                                    limit //
1318                    );
1319    
1320            }
1321    
1322            /**
1323             * send from {@link java.nio.DirectByteBuffer}, upto
1324             * {@link java.nio.ByteBuffer#remaining()} bytes
1325             * 
1326             * @param buffer
1327             *            buffer to send
1328             * @return <code>-1</code> : no buffer space (non-blocking only)<br>
1329             *         <code>=0</code> : timeout expired (blocking only)<br>
1330             *         <code>>0</code> : normal send, actual sent byte count<br>
1331             * @see #send2(int, int, int, boolean, ByteBuffer, int, int)
1332             */
1333            public int send(final ByteBuffer buffer) throws ExceptionUDT {
1334    
1335                    HelpUDT.checkBuffer(buffer);
1336    
1337                    final int position = buffer.position();
1338                    final int limit = buffer.limit();
1339                    final int remaining = buffer.remaining();
1340    
1341                    final int sizeSent = send2( //
1342                                    socketID, //
1343                                    type.code, //
1344                                    messageTimeTolive, //
1345                                    messageIsOrdered, //
1346                                    buffer, //
1347                                    position, //
1348                                    limit //
1349                    );
1350    
1351                    if (sizeSent <= 0) {
1352                            return sizeSent;
1353                    }
1354                    if (sizeSent <= remaining) {
1355                            buffer.position(position + sizeSent);
1356                            return sizeSent;
1357                    } else { // should not happen
1358                            log.error("sizeSent > remaining");
1359                            return 0;
1360                    }
1361    
1362            }
1363    
1364            /**
1365             * Send file to remote peer.
1366             * 
1367             * @see #sendFile0(int, String, long, long, int)
1368             */
1369            public long sendFile( //
1370                            final File file, //
1371                            final long offset, //
1372                            final long length//
1373            ) throws ExceptionUDT {
1374    
1375                    if (type == TypeUDT.DATAGRAM) {
1376                            throw new IllegalStateException("invalid socket type : " + type);
1377                    }
1378    
1379                    if (file == null || !file.exists() || !file.isFile() || !file.canRead()) {
1380                            throw new IllegalArgumentException("invalid file : " + file);
1381                    }
1382    
1383                    if (offset < 0 || offset > file.length()) {
1384                            throw new IllegalArgumentException("invalid offset : " + offset);
1385                    }
1386    
1387                    if (length < 0 || offset + length > file.length()) {
1388                            throw new IllegalArgumentException("invalid length : " + length);
1389                    }
1390    
1391                    final String path = file.getAbsolutePath();
1392    
1393                    final int block;
1394                    if (length > DEFAULT_FILE_BLOCK_SIZE) {
1395                            block = DEFAULT_FILE_BLOCK_SIZE;
1396                    } else {
1397                            block = (int) length;
1398                    }
1399    
1400                    return sendFile0(id(), path, offset, length, block);
1401    
1402            }
1403    
1404            //
1405    
1406            /**
1407             * Configure socket in strict blocking / strict non-blocking mode.
1408             * 
1409             * @param block
1410             *            true : set both send and receive to blocking mode; false : set
1411             *            both send and receive to non-blocking mode
1412             * @see java.nio.channels.SocketChannel#configureBlocking(boolean)
1413             */
1414            public void setBlocking(final boolean block) throws ExceptionUDT {
1415                    if (block) {
1416                            setOption(OptionUDT.Is_Receive_Synchronous, Boolean.TRUE);
1417                            setOption(OptionUDT.Is_Send_Synchronous, Boolean.TRUE);
1418                    } else {
1419                            setOption(OptionUDT.Is_Receive_Synchronous, Boolean.FALSE);
1420                            setOption(OptionUDT.Is_Send_Synchronous, Boolean.FALSE);
1421                    }
1422            }
1423    
1424            /**
1425             * Apply default settings for message mode.
1426             * <p>
1427             * IsOdered = true;<br>
1428             * TimeTolLive = INFINITE_TTL;<br>
1429             */
1430            public void setDefaultMessageSendMode() {
1431                    setMessageIsOdered(true);
1432                    setMessageTimeTolLive(INFINITE_TTL);
1433            }
1434    
1435            /**
1436             * default isOrdered value used by sendmsg mode
1437             * 
1438             * @see <a
1439             *      href="http://udt.sourceforge.net/udt4/doc/sendmsg.htm">UDT::sendmsg()</a>
1440             */
1441            public void setMessageIsOdered(final boolean isOrdered) {
1442                    messageIsOrdered = isOrdered;
1443            }
1444    
1445            /**
1446             * default timeToLive value used by sendmsg mode
1447             * 
1448             * @see <a
1449             *      href="http://udt.sourceforge.net/udt4/doc/sendmsg.htm">UDT::sendmsg()</a>
1450             */
1451            public void setMessageTimeTolLive(final int timeToLive) {
1452                    messageTimeTolive = timeToLive;
1453            }
1454    
1455            /**
1456             * @see #setOption0(int, Class, Object)
1457             */
1458            public <T> void setOption( //
1459                            final OptionUDT<T> option, //
1460                            final T value //
1461            ) throws ExceptionUDT {
1462    
1463                    if (option == null || value == null) {
1464                            throw new IllegalArgumentException(
1465                                            "option == null || value == null");
1466                    }
1467    
1468                    setOption0(option.code(), option.type(), value);
1469    
1470            }
1471    
1472            /**
1473             * @see <a
1474             *      href="http://udt.sourceforge.net/udt4/doc/opt.htm">UDT::setsockopt()</a>
1475             */
1476            protected native void setOption0( //
1477                            final int code, //
1478                            final Class<?> klaz, //
1479                            final Object value //
1480            ) throws ExceptionUDT;
1481    
1482            /**
1483             * Set maximum receive buffer size. Affects both protocol-level (UDT) and
1484             * kernel-level(UDP) settings.
1485             */
1486            public void setReceiveBufferSize(final int size) throws ExceptionUDT {
1487                    setOption(OptionUDT.Protocol_Receive_Buffer_Size, size);
1488                    setOption(OptionUDT.System_Receive_Buffer_Size, size);
1489            }
1490    
1491            public void setRendezvous(final boolean isOn) throws ExceptionUDT {
1492                    setOption(OptionUDT.Is_Randezvous_Connect_Enabled, isOn);
1493            }
1494    
1495            public void setReuseAddress(final boolean on) throws ExceptionUDT {
1496                    setOption(OptionUDT.Is_Address_Reuse_Enabled, on);
1497            }
1498    
1499            /**
1500             * Set maximum send buffer size. Affects both protocol-level (UDT) and
1501             * kernel-level(UDP) settings
1502             * 
1503             * @see java.net.Socket#setSendBufferSize(int)
1504             */
1505            public void setSendBufferSize(final int size) throws ExceptionUDT {
1506                    setOption(OptionUDT.Protocol_Send_Buffer_Size, size);
1507                    setOption(OptionUDT.System_Send_Buffer_Size, size);
1508            }
1509    
1510            public void setSoLinger(final boolean on, final int linger)
1511                            throws ExceptionUDT {
1512                    if (on) {
1513                            if (linger <= 0) {
1514                                    // keep JDK contract for setSoLinger parameters
1515                                    throw new IllegalArgumentException("linger <= 0");
1516                            }
1517                            setOption(OptionUDT.Time_To_Linger_On_Close, new LingerUDT(linger));
1518                    } else {
1519                            setOption(OptionUDT.Time_To_Linger_On_Close, LingerUDT.LINGER_ZERO);
1520                    }
1521            }
1522    
1523            /**
1524             * call timeout (milliseconds); Set a timeout on blocking Socket operations:
1525             * ServerSocket.accept(); SocketInputStream.read();
1526             * DatagramSocket.receive(); Enable/disable SO_TIMEOUT with the specified
1527             * timeout, in milliseconds. A timeout of zero is interpreted as an infinite
1528             * timeout.
1529             */
1530            public void setSoTimeout(/* non-final */int millisTimeout)
1531                            throws ExceptionUDT {
1532                    if (millisTimeout < 0) {
1533                            throw new IllegalArgumentException("timeout < 0");
1534                    }
1535                    if (millisTimeout == 0) {
1536                            // UDT uses different value for "infinite"
1537                            millisTimeout = TIMEOUT_INFINITE;
1538                    }
1539                    setOption(OptionUDT.Send_Timeout, millisTimeout);
1540                    setOption(OptionUDT.Receive_Timeout, millisTimeout);
1541            }
1542    
1543            /**
1544             * returns native status of underlying native UDT socket
1545             */
1546            public StatusUDT status() {
1547                    return StatusUDT.from(getStatus0());
1548            }
1549    
1550            //
1551            @Override
1552            public String toString() {
1553    
1554                    return String.format( //
1555                                    "[id: 0x%08x] %s %s bind=%s:%s peer=%s:%s", //
1556                                    socketID, //
1557                                    type, //
1558                                    status(), //
1559                                    getLocalInetAddress(), //
1560                                    getLocalInetPort(), //
1561                                    getRemoteInetAddress(), //
1562                                    getRemoteInetPort() //
1563                                    );
1564    
1565            }
1566    
1567            /**
1568             * Show current monitor status.
1569             */
1570            public String toStringMonitor() {
1571    
1572                    try {
1573                            updateMonitor(false);
1574                    } catch (final Exception e) {
1575                            return "failed to update monitor : " + e.getMessage();
1576                    }
1577    
1578                    final StringBuilder text = new StringBuilder(1024);
1579    
1580                    monitor.appendSnapshot(text);
1581    
1582                    return text.toString();
1583    
1584            }
1585    
1586            /**
1587             * Show current socket options.
1588             */
1589            public String toStringOptions() {
1590    
1591                    final StringBuilder text = new StringBuilder(1024);
1592    
1593                    OptionUDT.appendSnapshot(this, text);
1594    
1595                    return text.toString();
1596    
1597            }
1598    
1599            /**
1600             * message/stream socket type; read by JNI
1601             */
1602            public TypeUDT type() {
1603                    return type;
1604            }
1605    
1606            /**
1607             * Load updated statistics values into {@link #monitor} object. Must call
1608             * this methos only on connected socket.
1609             * 
1610             * @param makeClear
1611             *            true : reset all statistics with this call; false : keep
1612             *            collecting statistics, load updated values.
1613             * @see #updateMonitor0(boolean)
1614             */
1615            public void updateMonitor(final boolean makeClear) throws ExceptionUDT {
1616                    updateMonitor0(makeClear);
1617            }
1618    
1619            /**
1620             * @see <a
1621             *      href="http://udt.sourceforge.net/udt4/doc/trace.htm">UDT::perfmon</a>
1622             */
1623            protected native void updateMonitor0(final boolean makeClear)
1624                            throws ExceptionUDT;
1625    
1626    }