001    package dk.i1.sctp;
002    import java.net.*;
003    import java.util.Collection;
004    import java.util.ArrayList;
005    
006    /** An SCTP socket
007    An SCTP socket behaves in some ways like a TCP socket and in some ways like
008    a datagram socket.
009    <p>You cannot instantiate a SCTPSocket, but rather one of its two subclasses: {@link OneToOneSCTPSocket} and {@link OneToManySCTPSocket}.
010    
011     */
012    public class SCTPSocket {
013            static {
014                    System.loadLibrary("dk_i1_sctp");
015                    init();
016            }
017            private static native void init();
018            private long impl;
019            SCTPSocket(boolean one_to_many) throws SocketException {
020                    impl=0;
021                    open(one_to_many);
022            }
023            SCTPSocket(boolean one_to_many, int port) throws SocketException {
024                    impl=0;
025                    open(one_to_many);
026                    bind(port);
027            }
028            protected void finalize() throws Throwable {
029                    try {
030                            close();
031                    } finally {
032                            super.finalize();
033                    }
034            }
035            private native void open(boolean one_to_many) throws SocketException;
036            
037            /** Bind to an unspecified address/port.
038             * Binds the socket to a system-decided port and set of addresses.
039             * A socket can only be bound once.
040             */
041            public void bind() throws SocketException {
042                    bind(0);
043            }
044            /** Bind to a specific port.
045             * Binds the socket to the specified port, and system-decided set of addresses.
046             * A socket can only be bound once.
047             *@param port the SCTP port to bind to.
048             */
049            public void bind(int port) throws SocketException {
050                    bind((byte[])null,port);
051            }
052            /** Bind to a specific socket address.
053             * A socket can only be bound once.
054            * @deprecated An important feature of SCTP is multi-homing. This method binds the socket to a single interface and effectively disables multi-homing. This method is only here for completeness' sake.
055             */
056            public void bind(InetSocketAddress bindaddr) throws SocketException {
057                    bind(bindaddr.getAddress(),bindaddr.getPort());
058            }
059            /** Bind the socket to a spcific port/address.
060             * A socket can only be bound once.
061            * @deprecated An important feature of SCTP is multi-homing. This method binds the socket to a single interface and effectively disables multi-homing. This method is only here for completeness' sake.
062             */
063            public void bind(InetAddress addr, int port) throws SocketException {
064                    bind(addr.getAddress(),port);
065            }
066            private void bind(byte[] addr, int port) throws SocketException {
067                    bind_native(addr,port);
068            }
069            private native void bind_native(byte[] addr, int port) throws SocketException;
070            
071            /**Close the socket.
072             * Closes the socket. It is better to close the socket explicitly than rely or Java's GC.
073             * note: This method waits for any otustanding receive() calls to finish.
074             */
075            public native void close() throws SocketException;
076            
077            /**Returns the closed state of the socket.
078             *@since 0.5.3
079             */
080            public native boolean isClosed();
081            
082            /** Subscribe to specific SCTP notifications.
083             *
084             */
085            public void subscribeEvents(sctp_event_subscribe ses) throws SocketException {
086                    subscribeEvents(ses.sctp_data_io_event,
087                                    ses.sctp_association_event,
088                                    ses.sctp_address_event,
089                                    ses.sctp_send_failure_event,
090                                    ses.sctp_peer_error_event,
091                                    ses.sctp_shutdown_event,
092                                    ses.sctp_partial_delivery_event,
093                                    ses.sctp_adaptation_layer_event
094                                   );
095            }
096            private native void subscribeEvents(boolean sctp_data_io_event,
097                                                boolean sctp_association_event,
098                                                boolean sctp_address_event,
099                                                boolean sctp_send_failure_event,
100                                                boolean sctp_peer_error_event,
101                                                boolean sctp_shutdown_event,
102                                                boolean sctp_partial_delivery_event,
103                                                boolean sctp_adaptation_layer_event
104                                               ) throws SocketException;
105            
106            /**Configure the auto-close feature.
107             *Configures the auto-close timer, or disables it.
108             *@param seconds Number of seconds without traffic before automatically closing associations. 0 means disable.
109             */
110            public native void configureAutoClose(int seconds) throws SocketException;
111            
112            /**Set the blocking mode.
113             *The blocking mode on SCTP sockets affects only two operations: connect() and send().
114             *When configured in non-blocking connect() will return before the association is established and you should subscribe to the sctp_association_event (see {@link #subscribeEvents}).
115             *When configured in non-blocking send() may throw the {@link WouldBlockException} exception if the send call would block (probably due to OS buffers being full).
116             *@param block If true then send() and connect() any block. If false then send() and connect() will not block
117             */
118            public native void configureBlocking(boolean block) throws SocketException;
119            
120            /**Tells whether send() and connect() may block.
121             */
122            public native boolean isBlocking() throws SocketException;
123            
124            /**Enable/disable SCTP_NODELAY (disable/enable Nagle's algorithm).
125             * @param on   true to enable TCP_NODELAY, false to disable.
126             * @since 0.5.4
127             */
128            public native void setSctpNoDelay(boolean on) throws SocketException;
129            /**Tests if SCTP_NODELAY is enabled.
130             * @return a boolean indicating whether or not SCTP_NODELAY is enabled.
131             * @since 0.5.4
132             */
133            public native boolean getSctpNoDelay() throws SocketException;
134            
135            /** Set the parameters for a peer.
136             * Sets the parameters for a peer, heartbeat intervlal among others.
137             */
138            public void setPeerParameters(sctp_paddrparams spp) throws SocketException {
139                    setPeerParameters_native(spp.spp_assoc_id.id,
140                                             spp.spp_address==null?null:spp.spp_address.getAddress().getAddress(),
141                                             spp.spp_address==null?0:spp.spp_address.getPort(),
142                                             spp.spp_hbinterval,
143                                             spp.spp_pathmaxrxt,
144                                             spp.spp_pathmtu,
145                                             spp.spp_sackdelay,
146                                             spp.spp_flags,
147                                             spp.spp_ipv6_flowlabel,
148                                             spp.spp_ipv4_tos
149                                            );
150            }
151            private native void setPeerParameters_native(long  spp_assoc_id,
152                                                         byte[] spp_address_raw,
153                                                         int spp_address_port,
154                                                         int spp_hbinterval,
155                                                         short spp_pathmaxrxt,
156                                                         int spp_pathmtu,
157                                                         int spp_sackdelay,
158                                                         int spp_flags,
159                                                         int spp_ipv6_flowlabel,
160                                                         byte spp_ipv4_tos
161                                                        ) throws SocketException;
162            
163            /**Set default association parameters.
164             *Setting initialization parameters is effective only on an unconnected
165             *socket (for one-to-many style sockets only future associations are
166             *effected by the change).  With one-to-one style sockets, this option
167             *is inherited by sockets derived from a listener socket.
168             */
169            public void setInitMsg(sctp_initmsg im) throws SocketException {
170                    setInitMsg_native(im.sinit_num_ostreams, im.sinit_max_instreams,
171                                      im.sinit_max_attempts, im.sinit_max_init_timeo);
172            }
173            private native void setInitMsg_native(short sinit_num_ostreams,
174                                                  short sinit_max_instreams,
175                                                  short sinit_max_attempts,
176                                                  short sinit_max_init_timeo)
177                                                 throws SocketException;
178            
179            /**Enable inbound connections.
180             *Until listen() has been called inbound associations are not accepted.
181             */
182            public native void listen() throws SocketException;
183            
184            /**Create an association to a peer.
185             * Creates an association to a peer. Explicit association creation is
186             * not needed, but probably a good idea.
187             */
188            public void connect(InetSocketAddress addr) throws SocketException {
189                    connect(addr.getAddress(),addr.getPort());
190            }
191            /**Create an association to a peer.
192             * Creates an association to a peer. Explicit association creation is
193             * not needed, but probably a good idea.
194             */
195            public void connect(InetAddress addr, int port) throws SocketException {
196                    connect(addr.getAddress(),port);
197            }
198            private void connect(byte[] addr, int port) throws SocketException {
199                    connect_native(addr,port);
200            }
201            private native void connect_native(byte[] addr, int port) throws SocketException;
202            
203            /**Shut down an association.
204             */
205            public void disconnect(AssociationId assoc_id) throws SocketException {
206                    disconnect_native(assoc_id.id,true);
207            }
208            /**Shut down an association.
209             *@param assoc_id The association to shut down
210             *@param gracefully Controls whether the association is shut down gracefully with SCTP_EOF, or with SCTP_ABORT.
211             */
212            public void disconnect(AssociationId assoc_id, boolean gracefully) throws SocketException {
213                    disconnect_native(assoc_id.id,gracefully);
214            }
215            private native void disconnect_native(long assoc_id, boolean gracefully) throws SocketException;
216            
217            
218            /**Get local addressed uses by the socket.
219             *Retrieves the list of local addresses the socket can be contacted on.
220             *The list usually includes loopback-addresses, public ip-address and link-local addresses.
221             */
222            public Collection<InetAddress> getLocalInetAddresses() throws SocketException {
223                    return getLocalInetAddresses(AssociationId.default_);
224            }
225            /**Get local addresses used by the socket.
226             *Retrieves the list of local addresses the socket can be contacted on.
227             *The list usually includes loopback-addresses, public ip-address and link-local addresses.
228             */
229            public Collection<InetAddress> getLocalInetAddresses(AssociationId assoc_id) throws SocketException {
230                    Collection<InetAddress> col = new ArrayList<InetAddress>();
231                    getLocalInetAddresses_native(col,assoc_id.id);
232                    return col;
233            }
234            private native void getLocalInetAddresses_native(Collection<InetAddress> col, long assoc_id);
235            
236            /**Get local port.
237             * Retrieves the local port the socket is bound to. This is useful if you
238             * did not specify a specific port to bind to in the call to bind().
239             */
240            public native int getLocalInetPort() throws SocketException;
241            
242            /**Get addresses of a peer.
243             *Retrieves a list of known addresses of a peer, including non-reachable addresses.
244            */
245            public Collection<InetAddress> getPeerInetAddresses(AssociationId assoc_id) {
246                    Collection<InetAddress> col = new ArrayList<InetAddress>();
247                    getPeerInetAddresses_native(col,assoc_id.id);
248                    return col;
249            }
250            private native void getPeerInetAddresses_native(Collection<InetAddress> col, long assoc_id);
251            
252            public int getPeerInetPort(AssociationId assoc_id) throws SocketException {
253                    return getPeerInetPort_native(assoc_id.id);
254            }
255            private native int getPeerInetPort_native(long aid) throws SocketException;
256            
257            /**Probe if any unread chunks are pending
258             *@return true if any chunks are pending reading
259             */
260            public native boolean chunkAvailable() throws SocketException;
261            
262            /**Receive a data chunk or a notification. 
263             *Implemented as <tt>receive(0)</tt>
264             *@return a SCTPChunk, or, in some cases, null
265             */
266            public SCTPChunk receive() throws SocketException {
267                    return receive_native(0);
268            }
269            /**Receive a data chunk or a notification.
270             *If no events are available the call returns immediately with null.
271             *@return a SCTPChunk, or, in some cases, null
272             */
273            public SCTPChunk receiveNow() throws SocketException {
274                    return receive_native(-1);
275            }
276            /**Receive a data chunk or a notification.
277             *@param timeout Milliseconds to wait for an event. 0 means infinite. Must not be negative.
278             *@return a SCTPChunk, or, in some cases, null
279             */
280            public SCTPChunk receive(long timeout) throws SocketException, IllegalArgumentException {
281                    if(timeout<0)
282                            throw new IllegalArgumentException();
283                    return receive_native(timeout);
284            }
285            private native SCTPChunk receive_native(long timeout) throws SocketException;
286            
287            /**Send a datagram to a peer.
288             * Sends the data chunk to a peer. The peer is specified in sctpdata.sndrcvinfo.sinfo_assoc_id.
289             * <p>Example:</p>
290             <pre>
291            SCTPData data = new SCTPData(<i>raw_byte_array</i>);
292            data.sndrcvinfo.sinfo_assoc_id = <i>destination_association_id</i>;
293            sctp_socket.send(data);
294            </pre>
295             *@param sctpdata the data chunk to send.
296             *@throws SocketException if a socket error occurs.
297             *@throws WouldBlockException if the socket is non-blocking and outgoing OS buffers are full.
298             */
299            public void send(SCTPData sctpdata) throws SocketException, WouldBlockException {
300                    send_native(sctpdata.data,sctpdata.sndrcvinfo);
301            }
302            private native void send_native(byte[] data, sctp_sndrcvinfo sndrcvinfo) throws SocketException, WouldBlockException;
303            
304            /**Wake other threads from receive().
305             *Wakes 1 thread that is currently blocking in a receive() call.
306             *This method is only meant for clean shutdown, and is not as nice and the equivalent method in java.nio.Selector.
307             *The woken thread will return null.
308             */
309            public native void wakeup() throws SocketException;
310    }