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 }