2003-02-13 Michael Koch <konqueror@gmx.de>
[gcc.git] / libjava / java / net / Socket.java
1 /* Socket.java -- Client socket implementation
2 Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 package java.net;
39
40 import java.io.*;
41 import java.nio.channels.SocketChannel;
42 import java.nio.channels.IllegalBlockingModeException;
43
44 /* Written using on-line Java Platform 1.2 API Specification.
45 * Status: I believe all methods are implemented.
46 */
47
48 /**
49 * This class models a client site socket. A socket is a TCP/IP endpoint
50 * for network communications conceptually similar to a file handle.
51 * <p>
52 * This class does not actually do any work. Instead, it redirects all of
53 * its calls to a socket implementation object which implements the
54 * <code>SocketImpl</code> interface. The implementation class is
55 * instantiated by factory class that implements the
56 * <code>SocketImplFactory interface</code>. A default
57 * factory is provided, however the factory may be set by a call to
58 * the <code>setSocketImplFactory</code> method. Note that this may only be
59 * done once per virtual machine. If a subsequent attempt is made to set the
60 * factory, a <code>SocketException</code> will be thrown.
61 *
62 * @author Aaron M. Renn (arenn@urbanophile.com)
63 * @author Per Bothner (bothner@cygnus.com)
64 */
65 public class Socket
66 {
67
68 // Class Variables
69
70 /**
71 * This is the user SocketImplFactory for this class. If this variable is
72 * null, a default factory is used.
73 */
74 static SocketImplFactory factory;
75
76 // Instance Variables
77
78 /**
79 * The implementation object to which calls are redirected
80 */
81 SocketImpl impl;
82
83 private boolean inputShutdown;
84 private boolean outputShutdown;
85
86 SocketChannel ch; // this field must have been set if created by SocketChannel
87
88 private boolean closed = false;
89
90 // Constructors
91
92 /**
93 * Initializes a new instance of <code>Socket</code> object without
94 * connecting to a remote host. This useful for subclasses of socket that
95 * might want this behavior.
96 *
97 * @specnote This constructor is public since JDK 1.4
98 * @since 1.1
99 */
100 public Socket ()
101 {
102 if (factory != null)
103 impl = factory.createSocketImpl();
104 else
105 impl = new PlainSocketImpl();
106
107 inputShutdown = false;
108 outputShutdown = false;
109 }
110
111 /**
112 * Initializes a new instance of <code>Socket</code> object without
113 * connecting to a remote host. This is useful for subclasses of socket
114 * that might want this behavior.
115 * <p>
116 * Additionally, this socket will be created using the supplied
117 * implementation class instead the default class or one returned by a
118 * factory. This value can be <code>null</code>, but if it is, all instance
119 * methods in <code>Socket</code> should be overridden because most of them
120 * rely on this value being populated.
121 *
122 * @param impl The <code>SocketImpl</code> to use for this
123 * <code>Socket</code>
124 *
125 * @exception SocketException If an error occurs
126 *
127 * @since 1.1
128 */
129 protected Socket (SocketImpl impl) throws SocketException
130 {
131 this.impl = impl;
132 this.inputShutdown = false;
133 this.outputShutdown = false;
134 }
135
136 /**
137 * Initializes a new instance of <code>Socket</code> and connects to the
138 * hostname and port specified as arguments.
139 *
140 * @param host The name of the host to connect to
141 * @param port The port number to connect to
142 *
143 * @exception UnknownHostException If the hostname cannot be resolved to a
144 * network address.
145 * @exception IOException If an error occurs
146 * @exception SecurityException If a security manager exists and its
147 * checkConnect method doesn't allow the operation
148 */
149 public Socket (String host, int port)
150 throws UnknownHostException, IOException
151 {
152 this(InetAddress.getByName(host), port, null, 0, true);
153 }
154
155 /**
156 * Initializes a new instance of <code>Socket</code> and connects to the
157 * address and port number specified as arguments.
158 *
159 * @param address The address to connect to
160 * @param port The port number to connect to
161 *
162 * @exception IOException If an error occurs
163 * @exception SecurityException If a security manager exists and its
164 * checkConnect method doesn't allow the operation
165 */
166 public Socket (InetAddress address, int port)
167 throws IOException
168 {
169 this(address, port, null, 0, true);
170 }
171
172 /**
173 * Initializes a new instance of <code>Socket</code> that connects to the
174 * named host on the specified port and binds to the specified local address
175 * and port.
176 *
177 * @param host The name of the remote host to connect to.
178 * @param port The remote port to connect to.
179 * @param loadAddr The local address to bind to.
180 * @param localPort The local port to bind to.
181 *
182 * @exception SecurityException If the <code>SecurityManager</code>
183 * exists and does not allow a connection to the specified host/port or
184 * binding to the specified local host/port.
185 * @exception IOException If a connection error occurs.
186 *
187 * @since 1.1
188 */
189 public Socket (String host, int port,
190 InetAddress localAddr, int localPort) throws IOException
191 {
192 this(InetAddress.getByName(host), port, localAddr, localPort, true);
193 }
194
195 /**
196 * Initializes a new instance of <code>Socket</code> and connects to the
197 * address and port number specified as arguments, plus binds to the
198 * specified local address and port.
199 *
200 * @param address The remote address to connect to
201 * @param port The remote port to connect to
202 * @param localAddr The local address to connect to
203 * @param localPort The local port to connect to
204 *
205 * @exception IOException If an error occurs
206 * @exception SecurityException If a security manager exists and its
207 * checkConnect method doesn't allow the operation
208 *
209 * @since 1.1
210 */
211 public Socket (InetAddress address, int port,
212 InetAddress localAddr, int localPort) throws IOException
213 {
214 this(address, port, localAddr, localPort, true);
215 }
216
217 /**
218 * Initializes a new instance of <code>Socket</code> and connects to the
219 * hostname and port specified as arguments. If the stream argument is set
220 * to <code>true</code>, then a stream socket is created. If it is
221 * <code>false</code>, a datagram socket is created.
222 *
223 * @param host The name of the host to connect to
224 * @param port The port to connect to
225 * @param stream <code>true</code> for a stream socket, <code>false</code>
226 * for a datagram socket
227 *
228 * @exception IOException If an error occurs
229 * @exception SecurityException If a security manager exists and its
230 * checkConnect method doesn't allow the operation
231 *
232 * @deprecated Use the <code>DatagramSocket</code> class to create
233 * datagram oriented sockets.
234 */
235 public Socket (String host, int port, boolean stream) throws IOException
236 {
237 this(InetAddress.getByName(host), port, null, 0, stream);
238 }
239
240 /**
241 * Initializes a new instance of <code>Socket</code> and connects to the
242 * address and port number specified as arguments. If the stream param is
243 * <code>true</code>, a stream socket will be created, otherwise a datagram
244 * socket is created.
245 *
246 * @param host The address to connect to
247 * @param port The port number to connect to
248 * @param stream <code>true</code> to create a stream socket,
249 * <code>false</code> to create a datagram socket.
250 *
251 * @exception IOException If an error occurs
252 * @exception SecurityException If a security manager exists and its
253 * checkConnect method doesn't allow the operation
254 *
255 * @deprecated Use the <code>DatagramSocket</code> class to create
256 * datagram oriented sockets.
257 */
258 public Socket (InetAddress host, int port, boolean stream) throws IOException
259 {
260 this(host, port, null, 0, stream);
261 }
262
263 /**
264 * This constructor is where the real work takes place. Connect to the
265 * specified address and port. Use default local values if not specified,
266 * otherwise use the local host and port passed in. Create as stream or
267 * datagram based on "stream" argument.
268 * <p>
269 *
270 * @param raddr The remote address to connect to
271 * @param rport The remote port to connect to
272 * @param laddr The local address to connect to
273 * @param lport The local port to connect to
274 * @param stream true for a stream socket, false for a datagram socket
275 *
276 * @exception IOException If an error occurs
277 * @exception SecurityException If a security manager exists and its
278 * checkConnect method doesn't allow the operation
279 */
280 private Socket(InetAddress raddr, int rport, InetAddress laddr, int lport,
281 boolean stream) throws IOException
282 {
283 this();
284 this.inputShutdown = false;
285 this.outputShutdown = false;
286
287 if (impl == null)
288 throw new IOException("Cannot initialize Socket implementation");
289
290 SecurityManager sm = System.getSecurityManager();
291 if (sm != null)
292 sm.checkConnect(raddr.getHostName(), rport);
293
294 impl.create(stream);
295
296 // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port,
297 // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as
298 // that default. JDK 1.2 doc infers not to do a bind.
299 if (laddr != null)
300 impl.bind(laddr, lport);
301
302 if (raddr != null)
303 impl.connect(raddr, rport);
304 }
305
306 /**
307 * Binds the socket to the givent local address/port
308 *
309 * @param bindpoint The address/port to bind to
310 *
311 * @exception IOException If an error occurs
312 * @exception SecurityException If a security manager exists and its
313 * checkConnect method doesn't allow the operation
314 * @exception IllegalArgumentException If the address type is not supported
315 *
316 * @since 1.4
317 */
318 public void bind (SocketAddress bindpoint) throws IOException
319 {
320 if (closed)
321 throw new SocketException ("Socket is closed");
322
323 if ( !(bindpoint instanceof InetSocketAddress))
324 throw new IllegalArgumentException ();
325
326 InetSocketAddress tmp = (InetSocketAddress) bindpoint;
327 impl.bind (tmp.getAddress(), tmp.getPort());
328 }
329
330 /**
331 * Connects the socket with a remote address.
332 *
333 * @param endpoint The address to connect to
334 *
335 * @exception IOException If an error occurs
336 * @exception IllegalArgumentException If the addess type is not supported
337 * @exception IllegalBlockingModeException If this socket has an associated
338 * channel, and the channel is in non-blocking mode
339 *
340 * @since 1.4
341 */
342 public void connect (SocketAddress endpoint)
343 throws IOException
344 {
345 if (closed)
346 throw new SocketException ("Socket is closed");
347
348 if (! (endpoint instanceof InetSocketAddress))
349 throw new IllegalArgumentException ("Address type not supported");
350
351 if (ch != null && !ch.isBlocking ())
352 throw new IllegalBlockingModeException ();
353
354 impl.connect (endpoint, 0);
355 }
356
357 /**
358 * Connects the socket with a remote address. A timeout of zero is
359 * interpreted as an infinite timeout. The connection will then block
360 * until established or an error occurs.
361 *
362 * @param endpoint The address to connect to
363 *
364 * @exception IOException If an error occurs
365 * @exception IllegalArgumentException If the address type is not supported
366 * @exception IllegalBlockingModeException If this socket has an associated
367 * channel, and the channel is in non-blocking mode
368 * @exception SocketTimeoutException If the timeout is reached
369 *
370 * @since 1.4
371 */
372 public void connect (SocketAddress endpoint, int timeout)
373 throws IOException
374 {
375 if (closed)
376 throw new SocketException ("Socket is closed");
377
378 if (! (endpoint instanceof InetSocketAddress))
379 throw new IllegalArgumentException ("Address type not supported");
380
381 if (ch != null && !ch.isBlocking ())
382 throw new IllegalBlockingModeException ();
383
384 impl.connect (endpoint, timeout);
385 }
386
387 /**
388 * Returns the address of the remote end of the socket. If this socket
389 * is not connected, then <code>null</code> is returned.
390 *
391 * @return The remote address this socket is connected to
392 */
393 public InetAddress getInetAddress ()
394 {
395 if (impl != null)
396 return impl.getInetAddress();
397
398 return null;
399 }
400
401 /**
402 * Returns the local address to which this socket is bound. If this socket
403 * is not connected, then <code>null</code> is returned.
404 *
405 * @return The local address
406 *
407 * @since 1.1
408 */
409 public InetAddress getLocalAddress ()
410 {
411 if (impl == null)
412 return null;
413
414 InetAddress addr = null;
415 try
416 {
417 addr = (InetAddress)impl.getOption(SocketOptions.SO_BINDADDR);
418 }
419 catch(SocketException e)
420 {
421 // (hopefully) shouldn't happen
422 // throw new java.lang.InternalError
423 // ("Error in PlainSocketImpl.getOption");
424 return null;
425 }
426
427 // FIXME: According to libgcj, checkConnect() is supposed to be called
428 // before performing this operation. Problems: 1) We don't have the
429 // addr until after we do it, so we do a post check. 2). The docs I
430 // see don't require this in the Socket case, only DatagramSocket, but
431 // we'll assume they mean both.
432 SecurityManager sm = System.getSecurityManager();
433 if (sm != null)
434 sm.checkConnect(addr.getHostName(), getLocalPort());
435
436 return addr;
437 }
438
439 /**
440 * Returns the port number of the remote end of the socket connection. If
441 * this socket is not connected, then -1 is returned.
442 *
443 * @return The remote port this socket is connected to
444 */
445 public int getPort ()
446 {
447 if (impl != null)
448 return impl.getPort();
449
450 return -1;
451 }
452
453 /**
454 * Returns the local port number to which this socket is bound. If this
455 * socket is not connected, then -1 is returned.
456 *
457 * @return The local port
458 */
459 public int getLocalPort ()
460 {
461 if (impl != null)
462 return impl.getLocalPort();
463
464 return -1;
465 }
466
467 /**
468 * If the socket is already bound this returns the local SocketAddress,
469 * otherwise null
470 *
471 * @since 1.4
472 */
473 public SocketAddress getLocalSocketAddress()
474 {
475 InetAddress addr = getLocalAddress ();
476
477 if (addr == null)
478 return null;
479
480 return new InetSocketAddress (addr, impl.getLocalPort());
481 }
482
483 /**
484 * If the socket is already connected this returns the remote SocketAddress,
485 * otherwise null
486 *
487 * @since 1.4
488 */
489 public SocketAddress getRemoteSocketAddress()
490 {
491 if (!isConnected ())
492 return null;
493
494 return new InetSocketAddress (impl.getInetAddress (), impl.getPort ());
495 }
496
497 /**
498 * Returns an InputStream for reading from this socket.
499 *
500 * @return The InputStream object
501 *
502 * @exception IOException If an error occurs or Socket is not connected
503 */
504 public InputStream getInputStream () throws IOException
505 {
506 if (impl != null)
507 return(impl.getInputStream());
508
509 throw new IOException("Not connected");
510 }
511
512 /**
513 * Returns an OutputStream for writing to this socket.
514 *
515 * @return The OutputStream object
516 *
517 * @exception IOException If an error occurs or Socket is not connected
518 */
519 public OutputStream getOutputStream () throws IOException
520 {
521 if (impl != null)
522 return impl.getOutputStream();
523
524 throw new IOException("Not connected");
525 }
526
527 /**
528 * Sets the TCP_NODELAY option on the socket.
529 *
530 * @param on true to enable, false to disable
531 *
532 * @exception SocketException If an error occurs or Socket is not connected
533 *
534 * @since 1.1
535 */
536 public void setTcpNoDelay (boolean on) throws SocketException
537 {
538 if (impl == null)
539 throw new SocketException("Not connected");
540
541 impl.setOption(SocketOptions.TCP_NODELAY, new Boolean(on));
542 }
543
544 /**
545 * Tests whether or not the TCP_NODELAY option is set on the socket.
546 * Returns true if enabled, false if disabled. When on it disables the
547 * Nagle algorithm which means that packets are always send immediatly and
548 * never merged together to reduce network trafic.
549 *
550 * @return Whether or not TCP_NODELAY is set
551 *
552 * @exception SocketException If an error occurs or Socket not connected
553 *
554 * @since 1.1
555 */
556 public boolean getTcpNoDelay() throws SocketException
557 {
558 if (impl == null)
559 throw new SocketException("Not connected");
560
561 Object on = impl.getOption(SocketOptions.TCP_NODELAY);
562
563 if (on instanceof Boolean)
564 return(((Boolean)on).booleanValue());
565 else
566 throw new SocketException("Internal Error");
567 }
568
569 /**
570 * Sets the value of the SO_LINGER option on the socket. If the
571 * SO_LINGER option is set on a socket and there is still data waiting to
572 * be sent when the socket is closed, then the close operation will block
573 * until either that data is delivered or until the timeout period
574 * expires. The linger interval is specified in hundreths of a second
575 * (platform specific?)
576 *
577 * @param on true to enable SO_LINGER, false to disable
578 * @param linger The SO_LINGER timeout in hundreths of a second or -1 if
579 * SO_LINGER not set.
580 *
581 * @exception SocketException If an error occurs or Socket not connected
582 * @exception IllegalArgumentException If linger is negative
583 *
584 * @since 1.1
585 */
586 public void setSoLinger(boolean on, int linger) throws SocketException
587 {
588 if (impl == null)
589 throw new SocketException("No socket created");
590
591 if (on == true)
592 {
593 if (linger < 0)
594 throw new IllegalArgumentException("SO_LINGER must be >= 0");
595
596 if (linger > 65535)
597 linger = 65535;
598
599 impl.setOption(SocketOptions.SO_LINGER, new Integer(linger));
600 }
601 else
602 {
603 impl.setOption(SocketOptions.SO_LINGER, new Boolean(false));
604 }
605 }
606
607 /**
608 * Returns the value of the SO_LINGER option on the socket. If the
609 * SO_LINGER option is set on a socket and there is still data waiting to
610 * be sent when the socket is closed, then the close operation will block
611 * until either that data is delivered or until the timeout period
612 * expires. This method either returns the timeouts (in hundredths of
613 * of a second (platform specific?)) if SO_LINGER is set, or -1 if
614 * SO_LINGER is not set.
615 *
616 * @return The SO_LINGER timeout in hundreths of a second or -1
617 * if SO_LINGER not set
618 *
619 * @exception SocketException If an error occurs or Socket is not connected
620 *
621 * @since 1.1
622 */
623 public int getSoLinger() throws SocketException
624 {
625 if (impl == null)
626 throw new SocketException("Not connected");
627
628 Object linger = impl.getOption(SocketOptions.SO_LINGER);
629 if (linger instanceof Integer)
630 return(((Integer)linger).intValue());
631 else
632 return -1;
633 }
634
635 /**
636 * Sends urgent data through the socket
637 *
638 * @param data The data to send.
639 * Only the lowest eight bits of data are sent
640 *
641 * @exception IOException If an error occurs
642 *
643 * @since 1.4
644 */
645 public void sendUrgentData (int data) throws IOException
646 {
647 impl.sendUrgentData (data);
648 }
649
650 /**
651 * Enables/disables the SO_OOBINLINE option
652 *
653 * @param on True if SO_OOBLINE should be enabled
654 *
655 * @exception SocketException If an error occurs
656 *
657 * @since 1.4
658 */
659 public void setOOBInline (boolean on) throws SocketException
660 {
661 if (impl == null)
662 throw new SocketException("Not connected");
663
664 impl.setOption(SocketOptions.SO_OOBINLINE, new Boolean(on));
665 }
666
667 /**
668 * Returns the current setting of the SO_OOBINLINE option for this socket
669 *
670 * @exception SocketException If an error occurs
671 *
672 * @since 1.4
673 */
674 public boolean getOOBInline () throws SocketException
675 {
676 if (impl == null)
677 throw new SocketException("Not connected");
678
679 Object buf = impl.getOption(SocketOptions.SO_OOBINLINE);
680
681 if (buf instanceof Boolean)
682 return(((Boolean)buf).booleanValue());
683 else
684 throw new SocketException("Internal Error: Unexpected type");
685 }
686
687 /**
688 * Sets the value of the SO_TIMEOUT option on the socket. If this value
689 * is set, and an read/write is performed that does not complete within
690 * the timeout period, a short count is returned (or an EWOULDBLOCK signal
691 * would be sent in Unix if no data had been read). A value of 0 for
692 * this option implies that there is no timeout (ie, operations will
693 * block forever). On systems that have separate read and write timeout
694 * values, this method returns the read timeout. This
695 * value is in thousandths of a second (****????*****)
696 *
697 * @param timeout The length of the timeout in thousandth's of a second or
698 * 0 if not set
699 *
700 * @exception SocketException If an error occurs or Socket not connected
701 *
702 * @since 1.1
703 */
704 public synchronized void setSoTimeout (int timeout) throws SocketException
705 {
706 if (impl == null)
707 throw new SocketException("Not connected");
708
709 if (timeout < 0)
710 throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0");
711
712 impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
713 }
714
715 /**
716 * Returns the value of the SO_TIMEOUT option on the socket. If this value
717 * is set, and an read/write is performed that does not complete within
718 * the timeout period, a short count is returned (or an EWOULDBLOCK signal
719 * would be sent in Unix if no data had been read). A value of 0 for
720 * this option implies that there is no timeout (ie, operations will
721 * block forever). On systems that have separate read and write timeout
722 * values, this method returns the read timeout. This
723 * value is in thousandths of a second (implementation specific?).
724 *
725 * @return The length of the timeout in thousandth's of a second or 0
726 * if not set
727 *
728 * @exception SocketException If an error occurs or Socket not connected
729 *
730 * @since 1.1
731 */
732 public synchronized int getSoTimeout () throws SocketException
733 {
734 if (impl == null)
735 throw new SocketException("Not connected");
736
737 Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT);
738 if (timeout instanceof Integer)
739 return(((Integer)timeout).intValue());
740 else
741 return 0;
742 }
743
744 /**
745 * This method sets the value for the system level socket option
746 * SO_SNDBUF to the specified value. Note that valid values for this
747 * option are specific to a given operating system.
748 *
749 * @param size The new send buffer size.
750 *
751 * @exception SocketException If an error occurs or Socket not connected
752 * @exception IllegalArgumentException If size is 0 or negative
753 *
754 * @since 1.2
755 */
756 public void setSendBufferSize (int size) throws SocketException
757 {
758 if (impl == null)
759 throw new SocketException("Not connected");
760
761 if (size <= 0)
762 throw new IllegalArgumentException("SO_SNDBUF value must be > 0");
763
764 impl.setOption(SocketOptions.SO_SNDBUF, new Integer(size));
765 }
766
767 /**
768 * This method returns the value of the system level socket option
769 * SO_SNDBUF, which is used by the operating system to tune buffer
770 * sizes for data transfers.
771 *
772 * @return The send buffer size.
773 *
774 * @exception SocketException If an error occurs or socket not connected
775 *
776 * @since 1.2
777 */
778 public int getSendBufferSize () throws SocketException
779 {
780 if (impl == null)
781 throw new SocketException("Not connected");
782
783 Object buf = impl.getOption(SocketOptions.SO_SNDBUF);
784
785 if (buf instanceof Integer)
786 return(((Integer)buf).intValue());
787 else
788 throw new SocketException("Internal Error: Unexpected type");
789 }
790
791 /**
792 * This method sets the value for the system level socket option
793 * SO_RCVBUF to the specified value. Note that valid values for this
794 * option are specific to a given operating system.
795 *
796 * @param size The new receive buffer size.
797 *
798 * @exception SocketException If an error occurs or Socket is not connected
799 * @exception IllegalArgumentException If size is 0 or negative
800 *
801 * @since 1.2
802 */
803 public void setReceiveBufferSize (int size) throws SocketException
804 {
805 if (impl == null)
806 throw new SocketException("Not connected");
807
808 if (size <= 0)
809 throw new IllegalArgumentException("SO_RCVBUF value must be > 0");
810
811 impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size));
812 }
813
814 /**
815 * This method returns the value of the system level socket option
816 * SO_RCVBUF, which is used by the operating system to tune buffer
817 * sizes for data transfers.
818 *
819 * @return The receive buffer size.
820 *
821 * @exception SocketException If an error occurs or Socket is not connected
822 *
823 * @since 1.2
824 */
825 public int getReceiveBufferSize () throws SocketException
826 {
827 if (impl == null)
828 throw new SocketException("Not connected");
829
830 Object buf = impl.getOption(SocketOptions.SO_RCVBUF);
831
832 if (buf instanceof Integer)
833 return(((Integer)buf).intValue());
834 else
835 throw new SocketException("Internal Error: Unexpected type");
836 }
837
838 /**
839 * This method sets the value for the socket level socket option
840 * SO_KEEPALIVE.
841 *
842 * @param on True if SO_KEEPALIVE should be enabled
843 *
844 * @exception SocketException If an error occurs or Socket is not connected
845 *
846 * @since 1.3
847 */
848 public void setKeepAlive (boolean on) throws SocketException
849 {
850 if (impl == null)
851 throw new SocketException("Not connected");
852
853 impl.setOption(SocketOptions.SO_KEEPALIVE, new Boolean(on));
854 }
855
856 /**
857 * This method returns the value of the socket level socket option
858 * SO_KEEPALIVE.
859 *
860 * @return The setting
861 *
862 * @exception SocketException If an error occurs or Socket is not connected
863 *
864 * @since 1.3
865 */
866 public boolean getKeepAlive () throws SocketException
867 {
868 if (impl == null)
869 throw new SocketException("Not connected");
870
871 Object buf = impl.getOption(SocketOptions.SO_KEEPALIVE);
872
873 if (buf instanceof Boolean)
874 return(((Boolean)buf).booleanValue());
875 else
876 throw new SocketException("Internal Error: Unexpected type");
877 }
878
879 /**
880 * Closes the socket.
881 *
882 * @exception IOException If an error occurs
883 */
884 public synchronized void close () throws IOException
885 {
886 if (impl != null)
887 impl.close();
888
889 if (ch != null)
890 ch.close();
891
892 closed = true;
893 }
894
895 /**
896 * Converts this <code>Socket</code> to a <code>String</code>.
897 *
898 * @return The <code>String</code> representation of this <code>Socket</code>
899 */
900 public String toString ()
901 {
902 return("Socket " + impl);
903 }
904
905 // Class Methods
906
907 /**
908 * Sets the <code>SocketImplFactory</code>. This may be done only once per
909 * virtual machine. Subsequent attempts will generate a
910 * <code>SocketException</code>. Note that a <code>SecurityManager</code>
911 * check is made prior to setting the factory. If
912 * insufficient privileges exist to set the factory, then an
913 * <code>IOException</code> will be thrown.
914 *
915 * @exception SecurityException If the <code>SecurityManager</code> does
916 * not allow this operation.
917 * @exception SocketException If the SocketImplFactory is already defined
918 * @exception IOException If any other error occurs
919 */
920 public static synchronized void setSocketImplFactory (SocketImplFactory fac)
921 throws IOException
922 {
923 // See if already set
924 if (factory != null)
925 throw new SocketException("SocketImplFactory already defined");
926
927 // Check permissions
928 SecurityManager sm = System.getSecurityManager();
929 if (sm != null)
930 sm.checkSetFactory();
931
932 if (fac == null)
933 throw new SocketException("SocketImplFactory cannot be null");
934
935 factory = fac;
936 }
937
938 /**
939 * Closes the input side of the socket stream.
940 *
941 * @exception IOException If an error occurs.
942 *
943 * @since 1.3
944 */
945 public void shutdownInput() throws IOException
946 {
947 if (impl != null)
948 impl.shutdownInput();
949
950 inputShutdown = true;
951 }
952
953 /**
954 * Closes the output side of the socket stream.
955 *
956 * @exception IOException If an error occurs.
957 *
958 * @since 1.3
959 */
960 public void shutdownOutput() throws IOException
961 {
962 if (impl != null)
963 impl.shutdownOutput();
964
965 outputShutdown = true;
966 }
967
968 /**
969 * Returns the socket channel associated with this socket.
970 *
971 * It returns null if no associated socket exists.
972 *
973 * @since 1.4
974 */
975 public SocketChannel getChannel()
976 {
977 return ch;
978 }
979
980 /**
981 * Checks if the SO_REUSEADDR option is enabled
982 *
983 * @exception SocketException If an error occurs
984 *
985 * @since 1.4
986 */
987 public boolean getReuseAddress () throws SocketException
988 {
989 if (impl == null)
990 throw new SocketException ("Cannot initialize Socket implementation");
991
992 Object reuseaddr = impl.getOption (SocketOptions.SO_REUSEADDR);
993
994 if (!(reuseaddr instanceof Boolean))
995 throw new SocketException ("Internal Error");
996
997 return ((Boolean) reuseaddr).booleanValue ();
998 }
999
1000 /**
1001 * Enables/Disables the SO_REUSEADDR option
1002 *
1003 * @exception SocketException If an error occurs
1004 *
1005 * @since 1.4
1006 */
1007 public void setReuseAddress (boolean on) throws SocketException
1008 {
1009 if (impl == null)
1010 throw new SocketException ("Cannot initialize Socket implementation");
1011
1012 impl.setOption (SocketOptions.SO_REUSEADDR, new Boolean (on));
1013 }
1014
1015 /**
1016 * Returns the current traffic class
1017 *
1018 * @exception SocketException If an error occurs
1019 *
1020 * @see Socket:setTrafficClass
1021 *
1022 * @since 1.4
1023 */
1024 public int getTrafficClass () throws SocketException
1025 {
1026 if (impl == null)
1027 throw new SocketException ("Cannot initialize Socket implementation");
1028
1029 Object obj = impl.getOption(SocketOptions.IP_TOS);
1030
1031 if (obj instanceof Integer)
1032 return ((Integer) obj).intValue ();
1033 else
1034 throw new SocketException ("Unexpected type");
1035 }
1036
1037 /**
1038 * Sets the traffic class value
1039 *
1040 * @param tc The traffic class
1041 *
1042 * @exception SocketException If an error occurs
1043 * @exception IllegalArgumentException If tc value is illegal
1044 *
1045 * @see Socket:getTrafficClass
1046 *
1047 * @since 1.4
1048 */
1049 public void setTrafficClass (int tc) throws SocketException
1050 {
1051 if (impl == null)
1052 throw new SocketException ("Cannot initialize Socket implementation");
1053
1054 if (tc < 0 || tc > 255)
1055 throw new IllegalArgumentException();
1056
1057 impl.setOption (SocketOptions.IP_TOS, new Integer (tc));
1058 }
1059
1060 /**
1061 * Checks if the socket is connected
1062 *
1063 * @since 1.4
1064 */
1065 public boolean isConnected ()
1066 {
1067 return impl.getInetAddress () != null;
1068 }
1069
1070 /**
1071 * Checks if the socket is already bound.
1072 *
1073 * @since 1.4
1074 */
1075 public boolean isBound ()
1076 {
1077 return getLocalAddress () != null;
1078 }
1079
1080 /**
1081 * Checks if the socket is closed.
1082 *
1083 * @since 1.4
1084 */
1085 public boolean isClosed ()
1086 {
1087 return closed;
1088 }
1089
1090 /**
1091 * Checks if the socket's input stream is shutdown
1092 *
1093 * @since 1.4
1094 */
1095 public boolean isInputShutdown ()
1096 {
1097 return inputShutdown;
1098 }
1099
1100 /**
1101 * Checks if the socket's output stream is shutdown
1102 *
1103 * @since 1.4
1104 */
1105 public boolean isOutputShutdown ()
1106 {
1107 return outputShutdown;
1108 }
1109 }