2003-06-17 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.InputStream;
41 import java.io.IOException;
42 import java.io.OutputStream;
43 import java.nio.channels.SocketChannel;
44 import java.nio.channels.IllegalBlockingModeException;
45
46 /* Written using on-line Java Platform 1.2 API Specification.
47 * Status: I believe all methods are implemented.
48 */
49
50 /**
51 * This class models a client site socket. A socket is a TCP/IP endpoint
52 * for network communications conceptually similar to a file handle.
53 * <p>
54 * This class does not actually do any work. Instead, it redirects all of
55 * its calls to a socket implementation object which implements the
56 * <code>SocketImpl</code> interface. The implementation class is
57 * instantiated by factory class that implements the
58 * <code>SocketImplFactory interface</code>. A default
59 * factory is provided, however the factory may be set by a call to
60 * the <code>setSocketImplFactory</code> method. Note that this may only be
61 * done once per virtual machine. If a subsequent attempt is made to set the
62 * factory, a <code>SocketException</code> will be thrown.
63 *
64 * @author Aaron M. Renn (arenn@urbanophile.com)
65 * @author Per Bothner (bothner@cygnus.com)
66 */
67 public class Socket
68 {
69
70 // Class Variables
71
72 /**
73 * This is the user SocketImplFactory for this class. If this variable is
74 * null, a default factory is used.
75 */
76 static SocketImplFactory factory;
77
78 // Instance Variables
79
80 /**
81 * The implementation object to which calls are redirected
82 */
83 SocketImpl impl;
84
85 private boolean inputShutdown;
86 private boolean outputShutdown;
87
88 SocketChannel ch; // this field must have been set if created by SocketChannel
89
90 private boolean closed = false;
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
285 if (raddr == null)
286 throw new NullPointerException ();
287
288 if (impl == null)
289 throw new IOException("Cannot initialize Socket implementation");
290
291 SecurityManager sm = System.getSecurityManager();
292 if (sm != null)
293 sm.checkConnect(raddr.getHostName(), rport);
294
295 // bind socket
296 SocketAddress bindaddr =
297 laddr == null ? null : new InetSocketAddress (laddr, lport);
298 bind (bindaddr);
299
300 // connect socket
301 connect (new InetSocketAddress (raddr, rport));
302
303 // FIXME: JCL p. 1586 says if localPort is unspecified, bind to any port,
304 // i.e. '0' and if localAddr is unspecified, use getLocalAddress() as
305 // that default. JDK 1.2 doc infers not to do a bind.
306 }
307
308 /**
309 * Binds the socket to the givent local address/port
310 *
311 * @param bindpoint The address/port to bind to
312 *
313 * @exception IOException If an error occurs
314 * @exception SecurityException If a security manager exists and its
315 * checkConnect method doesn't allow the operation
316 * @exception IllegalArgumentException If the address type is not supported
317 *
318 * @since 1.4
319 */
320 public void bind (SocketAddress bindpoint) throws IOException
321 {
322 if (closed)
323 throw new SocketException ("Socket is closed");
324
325 // XXX: JDK 1.4.1 API documentation says that if bindpoint is null the
326 // socket will be bound to an ephemeral port and a valid local address.
327 if (bindpoint == null)
328 bindpoint = new InetSocketAddress (InetAddress.ANY_IF, 0);
329
330 if ( !(bindpoint instanceof InetSocketAddress))
331 throw new IllegalArgumentException ();
332
333 InetSocketAddress tmp = (InetSocketAddress) bindpoint;
334
335 // create socket
336 impl.create (true);
337
338 // bind to address/port
339 try
340 {
341 impl.bind (tmp.getAddress(), tmp.getPort());
342 }
343 catch (IOException exception)
344 {
345 impl.close ();
346 throw exception;
347 }
348 catch (RuntimeException exception)
349 {
350 impl.close ();
351 throw exception;
352 }
353 catch (Error error)
354 {
355 impl.close ();
356 throw error;
357 }
358 }
359
360 /**
361 * Connects the socket with a remote address.
362 *
363 * @param endpoint The address to connect to
364 *
365 * @exception IOException If an error occurs
366 * @exception IllegalArgumentException If the addess type is not supported
367 * @exception IllegalBlockingModeException If this socket has an associated
368 * channel, and the channel is in non-blocking mode
369 *
370 * @since 1.4
371 */
372 public void connect (SocketAddress endpoint)
373 throws IOException
374 {
375 connect (endpoint, 0);
376 }
377
378 /**
379 * Connects the socket with a remote address. A timeout of zero is
380 * interpreted as an infinite timeout. The connection will then block
381 * until established or an error occurs.
382 *
383 * @param endpoint The address to connect to
384 *
385 * @exception IOException If an error occurs
386 * @exception IllegalArgumentException If the address type is not supported
387 * @exception IllegalBlockingModeException If this socket has an associated
388 * channel, and the channel is in non-blocking mode
389 * @exception SocketTimeoutException If the timeout is reached
390 *
391 * @since 1.4
392 */
393 public void connect (SocketAddress endpoint, int timeout)
394 throws IOException
395 {
396 if (closed)
397 throw new SocketException ("Socket is closed");
398
399 if (! (endpoint instanceof InetSocketAddress))
400 throw new IllegalArgumentException ("Address type not supported");
401
402 if (ch != null && !ch.isBlocking ())
403 throw new IllegalBlockingModeException ();
404
405 if (!isBound ())
406 bind (null);
407
408 try
409 {
410 impl.connect (endpoint, timeout);
411 }
412 catch (IOException exception)
413 {
414 impl.close ();
415 throw exception;
416 }
417 catch (RuntimeException exception)
418 {
419 impl.close ();
420 throw exception;
421 }
422 catch (Error error)
423 {
424 impl.close ();
425 throw error;
426 }
427 }
428
429 /**
430 * Returns the address of the remote end of the socket. If this socket
431 * is not connected, then <code>null</code> is returned.
432 *
433 * @return The remote address this socket is connected to
434 */
435 public InetAddress getInetAddress ()
436 {
437 if (impl != null)
438 return impl.getInetAddress();
439
440 return null;
441 }
442
443 /**
444 * Returns the local address to which this socket is bound. If this socket
445 * is not connected, then <code>null</code> is returned.
446 *
447 * @return The local address
448 *
449 * @since 1.1
450 */
451 public InetAddress getLocalAddress ()
452 {
453 if (impl == null)
454 return null;
455
456 InetAddress addr = null;
457 try
458 {
459 addr = (InetAddress)impl.getOption(SocketOptions.SO_BINDADDR);
460 }
461 catch(SocketException e)
462 {
463 // (hopefully) shouldn't happen
464 // throw new java.lang.InternalError
465 // ("Error in PlainSocketImpl.getOption");
466 return null;
467 }
468
469 // FIXME: According to libgcj, checkConnect() is supposed to be called
470 // before performing this operation. Problems: 1) We don't have the
471 // addr until after we do it, so we do a post check. 2). The docs I
472 // see don't require this in the Socket case, only DatagramSocket, but
473 // we'll assume they mean both.
474 SecurityManager sm = System.getSecurityManager();
475 if (sm != null)
476 sm.checkConnect(addr.getHostName(), getLocalPort());
477
478 return addr;
479 }
480
481 /**
482 * Returns the port number of the remote end of the socket connection. If
483 * this socket is not connected, then -1 is returned.
484 *
485 * @return The remote port this socket is connected to
486 */
487 public int getPort ()
488 {
489 if (impl != null)
490 return impl.getPort();
491
492 return -1;
493 }
494
495 /**
496 * Returns the local port number to which this socket is bound. If this
497 * socket is not connected, then -1 is returned.
498 *
499 * @return The local port
500 */
501 public int getLocalPort ()
502 {
503 if (impl != null)
504 return impl.getLocalPort();
505
506 return -1;
507 }
508
509 /**
510 * If the socket is already bound this returns the local SocketAddress,
511 * otherwise null
512 *
513 * @since 1.4
514 */
515 public SocketAddress getLocalSocketAddress()
516 {
517 InetAddress addr = getLocalAddress ();
518
519 if (addr == null)
520 return null;
521
522 return new InetSocketAddress (addr, impl.getLocalPort());
523 }
524
525 /**
526 * If the socket is already connected this returns the remote SocketAddress,
527 * otherwise null
528 *
529 * @since 1.4
530 */
531 public SocketAddress getRemoteSocketAddress()
532 {
533 if (!isConnected ())
534 return null;
535
536 return new InetSocketAddress (impl.getInetAddress (), impl.getPort ());
537 }
538
539 /**
540 * Returns an InputStream for reading from this socket.
541 *
542 * @return The InputStream object
543 *
544 * @exception IOException If an error occurs or Socket is not connected
545 */
546 public InputStream getInputStream () throws IOException
547 {
548 if (impl != null)
549 return(impl.getInputStream());
550
551 throw new IOException("Not connected");
552 }
553
554 /**
555 * Returns an OutputStream for writing to this socket.
556 *
557 * @return The OutputStream object
558 *
559 * @exception IOException If an error occurs or Socket is not connected
560 */
561 public OutputStream getOutputStream () throws IOException
562 {
563 if (impl != null)
564 return impl.getOutputStream();
565
566 throw new IOException("Not connected");
567 }
568
569 /**
570 * Sets the TCP_NODELAY option on the socket.
571 *
572 * @param on true to enable, false to disable
573 *
574 * @exception SocketException If an error occurs or Socket is not connected
575 *
576 * @since 1.1
577 */
578 public void setTcpNoDelay (boolean on) throws SocketException
579 {
580 if (impl == null)
581 throw new SocketException("Not connected");
582
583 impl.setOption(SocketOptions.TCP_NODELAY, new Boolean(on));
584 }
585
586 /**
587 * Tests whether or not the TCP_NODELAY option is set on the socket.
588 * Returns true if enabled, false if disabled. When on it disables the
589 * Nagle algorithm which means that packets are always send immediatly and
590 * never merged together to reduce network trafic.
591 *
592 * @return Whether or not TCP_NODELAY is set
593 *
594 * @exception SocketException If an error occurs or Socket not connected
595 *
596 * @since 1.1
597 */
598 public boolean getTcpNoDelay() throws SocketException
599 {
600 if (impl == null)
601 throw new SocketException("Not connected");
602
603 Object on = impl.getOption(SocketOptions.TCP_NODELAY);
604
605 if (on instanceof Boolean)
606 return(((Boolean)on).booleanValue());
607 else
608 throw new SocketException("Internal Error");
609 }
610
611 /**
612 * Sets the value of the SO_LINGER option on the socket. If the
613 * SO_LINGER option is set on a socket and there is still data waiting to
614 * be sent when the socket is closed, then the close operation will block
615 * until either that data is delivered or until the timeout period
616 * expires. The linger interval is specified in hundreths of a second
617 * (platform specific?)
618 *
619 * @param on true to enable SO_LINGER, false to disable
620 * @param linger The SO_LINGER timeout in hundreths of a second or -1 if
621 * SO_LINGER not set.
622 *
623 * @exception SocketException If an error occurs or Socket not connected
624 * @exception IllegalArgumentException If linger is negative
625 *
626 * @since 1.1
627 */
628 public void setSoLinger(boolean on, int linger) throws SocketException
629 {
630 if (impl == null)
631 throw new SocketException("No socket created");
632
633 if (on == true)
634 {
635 if (linger < 0)
636 throw new IllegalArgumentException("SO_LINGER must be >= 0");
637
638 if (linger > 65535)
639 linger = 65535;
640
641 impl.setOption(SocketOptions.SO_LINGER, new Integer(linger));
642 }
643 else
644 {
645 impl.setOption(SocketOptions.SO_LINGER, new Boolean(false));
646 }
647 }
648
649 /**
650 * Returns the value of the SO_LINGER option on the socket. If the
651 * SO_LINGER option is set on a socket and there is still data waiting to
652 * be sent when the socket is closed, then the close operation will block
653 * until either that data is delivered or until the timeout period
654 * expires. This method either returns the timeouts (in hundredths of
655 * of a second (platform specific?)) if SO_LINGER is set, or -1 if
656 * SO_LINGER is not set.
657 *
658 * @return The SO_LINGER timeout in hundreths of a second or -1
659 * if SO_LINGER not set
660 *
661 * @exception SocketException If an error occurs or Socket is not connected
662 *
663 * @since 1.1
664 */
665 public int getSoLinger() throws SocketException
666 {
667 if (impl == null)
668 throw new SocketException("Not connected");
669
670 Object linger = impl.getOption(SocketOptions.SO_LINGER);
671 if (linger instanceof Integer)
672 return(((Integer)linger).intValue());
673 else
674 return -1;
675 }
676
677 /**
678 * Sends urgent data through the socket
679 *
680 * @param data The data to send.
681 * Only the lowest eight bits of data are sent
682 *
683 * @exception IOException If an error occurs
684 *
685 * @since 1.4
686 */
687 public void sendUrgentData (int data) throws IOException
688 {
689 impl.sendUrgentData (data);
690 }
691
692 /**
693 * Enables/disables the SO_OOBINLINE option
694 *
695 * @param on True if SO_OOBLINE should be enabled
696 *
697 * @exception SocketException If an error occurs
698 *
699 * @since 1.4
700 */
701 public void setOOBInline (boolean on) throws SocketException
702 {
703 if (impl == null)
704 throw new SocketException("Not connected");
705
706 impl.setOption(SocketOptions.SO_OOBINLINE, new Boolean(on));
707 }
708
709 /**
710 * Returns the current setting of the SO_OOBINLINE option for this socket
711 *
712 * @exception SocketException If an error occurs
713 *
714 * @since 1.4
715 */
716 public boolean getOOBInline () throws SocketException
717 {
718 if (impl == null)
719 throw new SocketException("Not connected");
720
721 Object buf = impl.getOption(SocketOptions.SO_OOBINLINE);
722
723 if (buf instanceof Boolean)
724 return(((Boolean)buf).booleanValue());
725 else
726 throw new SocketException("Internal Error: Unexpected type");
727 }
728
729 /**
730 * Sets the value of the SO_TIMEOUT option on the socket. If this value
731 * is set, and an read/write is performed that does not complete within
732 * the timeout period, a short count is returned (or an EWOULDBLOCK signal
733 * would be sent in Unix if no data had been read). A value of 0 for
734 * this option implies that there is no timeout (ie, operations will
735 * block forever). On systems that have separate read and write timeout
736 * values, this method returns the read timeout. This
737 * value is in milliseconds.
738 *
739 * @param timeout The length of the timeout in milliseconds, or
740 * 0 to indicate no timeout.
741 *
742 * @exception SocketException If an error occurs or Socket not connected
743 *
744 * @since 1.1
745 */
746 public synchronized void setSoTimeout (int timeout) throws SocketException
747 {
748 if (impl == null)
749 throw new SocketException("Not connected");
750
751 if (timeout < 0)
752 throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0");
753
754 impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
755 }
756
757 /**
758 * Returns the value of the SO_TIMEOUT option on the socket. If this value
759 * is set, and an read/write is performed that does not complete within
760 * the timeout period, a short count is returned (or an EWOULDBLOCK signal
761 * would be sent in Unix if no data had been read). A value of 0 for
762 * this option implies that there is no timeout (ie, operations will
763 * block forever). On systems that have separate read and write timeout
764 * values, this method returns the read timeout. This
765 * value is in thousandths of a second (implementation specific?).
766 *
767 * @return The length of the timeout in thousandth's of a second or 0
768 * if not set
769 *
770 * @exception SocketException If an error occurs or Socket not connected
771 *
772 * @since 1.1
773 */
774 public synchronized int getSoTimeout () throws SocketException
775 {
776 if (impl == null)
777 throw new SocketException("Not connected");
778
779 Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT);
780 if (timeout instanceof Integer)
781 return(((Integer)timeout).intValue());
782 else
783 return 0;
784 }
785
786 /**
787 * This method sets the value for the system level socket option
788 * SO_SNDBUF to the specified value. Note that valid values for this
789 * option are specific to a given operating system.
790 *
791 * @param size The new send buffer size.
792 *
793 * @exception SocketException If an error occurs or Socket not connected
794 * @exception IllegalArgumentException If size is 0 or negative
795 *
796 * @since 1.2
797 */
798 public void setSendBufferSize (int size) throws SocketException
799 {
800 if (impl == null)
801 throw new SocketException("Not connected");
802
803 if (size <= 0)
804 throw new IllegalArgumentException("SO_SNDBUF value must be > 0");
805
806 impl.setOption(SocketOptions.SO_SNDBUF, new Integer(size));
807 }
808
809 /**
810 * This method returns the value of the system level socket option
811 * SO_SNDBUF, which is used by the operating system to tune buffer
812 * sizes for data transfers.
813 *
814 * @return The send buffer size.
815 *
816 * @exception SocketException If an error occurs or socket not connected
817 *
818 * @since 1.2
819 */
820 public int getSendBufferSize () throws SocketException
821 {
822 if (impl == null)
823 throw new SocketException("Not connected");
824
825 Object buf = impl.getOption(SocketOptions.SO_SNDBUF);
826
827 if (buf instanceof Integer)
828 return(((Integer)buf).intValue());
829 else
830 throw new SocketException("Internal Error: Unexpected type");
831 }
832
833 /**
834 * This method sets the value for the system level socket option
835 * SO_RCVBUF to the specified value. Note that valid values for this
836 * option are specific to a given operating system.
837 *
838 * @param size The new receive buffer size.
839 *
840 * @exception SocketException If an error occurs or Socket is not connected
841 * @exception IllegalArgumentException If size is 0 or negative
842 *
843 * @since 1.2
844 */
845 public void setReceiveBufferSize (int size) throws SocketException
846 {
847 if (impl == null)
848 throw new SocketException("Not connected");
849
850 if (size <= 0)
851 throw new IllegalArgumentException("SO_RCVBUF value must be > 0");
852
853 impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size));
854 }
855
856 /**
857 * This method returns the value of the system level socket option
858 * SO_RCVBUF, which is used by the operating system to tune buffer
859 * sizes for data transfers.
860 *
861 * @return The receive buffer size.
862 *
863 * @exception SocketException If an error occurs or Socket is not connected
864 *
865 * @since 1.2
866 */
867 public int getReceiveBufferSize () throws SocketException
868 {
869 if (impl == null)
870 throw new SocketException("Not connected");
871
872 Object buf = impl.getOption(SocketOptions.SO_RCVBUF);
873
874 if (buf instanceof Integer)
875 return(((Integer)buf).intValue());
876 else
877 throw new SocketException("Internal Error: Unexpected type");
878 }
879
880 /**
881 * This method sets the value for the socket level socket option
882 * SO_KEEPALIVE.
883 *
884 * @param on True if SO_KEEPALIVE should be enabled
885 *
886 * @exception SocketException If an error occurs or Socket is not connected
887 *
888 * @since 1.3
889 */
890 public void setKeepAlive (boolean on) throws SocketException
891 {
892 if (impl == null)
893 throw new SocketException("Not connected");
894
895 impl.setOption(SocketOptions.SO_KEEPALIVE, new Boolean(on));
896 }
897
898 /**
899 * This method returns the value of the socket level socket option
900 * SO_KEEPALIVE.
901 *
902 * @return The setting
903 *
904 * @exception SocketException If an error occurs or Socket is not connected
905 *
906 * @since 1.3
907 */
908 public boolean getKeepAlive () throws SocketException
909 {
910 if (impl == null)
911 throw new SocketException("Not connected");
912
913 Object buf = impl.getOption(SocketOptions.SO_KEEPALIVE);
914
915 if (buf instanceof Boolean)
916 return(((Boolean)buf).booleanValue());
917 else
918 throw new SocketException("Internal Error: Unexpected type");
919 }
920
921 /**
922 * Closes the socket.
923 *
924 * @exception IOException If an error occurs
925 */
926 public synchronized void close () throws IOException
927 {
928 if (impl != null)
929 impl.close();
930
931 if (ch != null)
932 ch.close();
933
934 closed = true;
935 }
936
937 /**
938 * Converts this <code>Socket</code> to a <code>String</code>.
939 *
940 * @return The <code>String</code> representation of this <code>Socket</code>
941 */
942 public String toString ()
943 {
944 return("Socket " + impl);
945 }
946
947 // Class Methods
948
949 /**
950 * Sets the <code>SocketImplFactory</code>. This may be done only once per
951 * virtual machine. Subsequent attempts will generate a
952 * <code>SocketException</code>. Note that a <code>SecurityManager</code>
953 * check is made prior to setting the factory. If
954 * insufficient privileges exist to set the factory, then an
955 * <code>IOException</code> will be thrown.
956 *
957 * @exception SecurityException If the <code>SecurityManager</code> does
958 * not allow this operation.
959 * @exception SocketException If the SocketImplFactory is already defined
960 * @exception IOException If any other error occurs
961 */
962 public static synchronized void setSocketImplFactory (SocketImplFactory fac)
963 throws IOException
964 {
965 // See if already set
966 if (factory != null)
967 throw new SocketException("SocketImplFactory already defined");
968
969 // Check permissions
970 SecurityManager sm = System.getSecurityManager();
971 if (sm != null)
972 sm.checkSetFactory();
973
974 if (fac == null)
975 throw new SocketException("SocketImplFactory cannot be null");
976
977 factory = fac;
978 }
979
980 /**
981 * Closes the input side of the socket stream.
982 *
983 * @exception IOException If an error occurs.
984 *
985 * @since 1.3
986 */
987 public void shutdownInput() throws IOException
988 {
989 if (impl != null)
990 impl.shutdownInput();
991
992 inputShutdown = true;
993 }
994
995 /**
996 * Closes the output side of the socket stream.
997 *
998 * @exception IOException If an error occurs.
999 *
1000 * @since 1.3
1001 */
1002 public void shutdownOutput() throws IOException
1003 {
1004 if (impl != null)
1005 impl.shutdownOutput();
1006
1007 outputShutdown = true;
1008 }
1009
1010 /**
1011 * Returns the socket channel associated with this socket.
1012 *
1013 * It returns null if no associated socket exists.
1014 *
1015 * @since 1.4
1016 */
1017 public SocketChannel getChannel()
1018 {
1019 return ch;
1020 }
1021
1022 /**
1023 * Checks if the SO_REUSEADDR option is enabled
1024 *
1025 * @exception SocketException If an error occurs
1026 *
1027 * @since 1.4
1028 */
1029 public boolean getReuseAddress () throws SocketException
1030 {
1031 if (impl == null)
1032 throw new SocketException ("Cannot initialize Socket implementation");
1033
1034 Object reuseaddr = impl.getOption (SocketOptions.SO_REUSEADDR);
1035
1036 if (!(reuseaddr instanceof Boolean))
1037 throw new SocketException ("Internal Error");
1038
1039 return ((Boolean) reuseaddr).booleanValue ();
1040 }
1041
1042 /**
1043 * Enables/Disables the SO_REUSEADDR option
1044 *
1045 * @exception SocketException If an error occurs
1046 *
1047 * @since 1.4
1048 */
1049 public void setReuseAddress (boolean on) throws SocketException
1050 {
1051 if (impl == null)
1052 throw new SocketException ("Cannot initialize Socket implementation");
1053
1054 impl.setOption (SocketOptions.SO_REUSEADDR, new Boolean (on));
1055 }
1056
1057 /**
1058 * Returns the current traffic class
1059 *
1060 * @exception SocketException If an error occurs
1061 *
1062 * @see Socket#setTrafficClass(int tc)
1063 *
1064 * @since 1.4
1065 */
1066 public int getTrafficClass () throws SocketException
1067 {
1068 if (impl == null)
1069 throw new SocketException ("Cannot initialize Socket implementation");
1070
1071 Object obj = impl.getOption(SocketOptions.IP_TOS);
1072
1073 if (obj instanceof Integer)
1074 return ((Integer) obj).intValue ();
1075 else
1076 throw new SocketException ("Unexpected type");
1077 }
1078
1079 /**
1080 * Sets the traffic class value
1081 *
1082 * @param tc The traffic class
1083 *
1084 * @exception SocketException If an error occurs
1085 * @exception IllegalArgumentException If tc value is illegal
1086 *
1087 * @see Socket#getTrafficClass()
1088 *
1089 * @since 1.4
1090 */
1091 public void setTrafficClass (int tc) throws SocketException
1092 {
1093 if (impl == null)
1094 throw new SocketException ("Cannot initialize Socket implementation");
1095
1096 if (tc < 0 || tc > 255)
1097 throw new IllegalArgumentException();
1098
1099 impl.setOption (SocketOptions.IP_TOS, new Integer (tc));
1100 }
1101
1102 /**
1103 * Checks if the socket is connected
1104 *
1105 * @since 1.4
1106 */
1107 public boolean isConnected ()
1108 {
1109 return impl.getInetAddress () != null;
1110 }
1111
1112 /**
1113 * Checks if the socket is already bound.
1114 *
1115 * @since 1.4
1116 */
1117 public boolean isBound ()
1118 {
1119 return getLocalAddress () != null;
1120 }
1121
1122 /**
1123 * Checks if the socket is closed.
1124 *
1125 * @since 1.4
1126 */
1127 public boolean isClosed ()
1128 {
1129 return closed;
1130 }
1131
1132 /**
1133 * Checks if the socket's input stream is shutdown
1134 *
1135 * @since 1.4
1136 */
1137 public boolean isInputShutdown ()
1138 {
1139 return inputShutdown;
1140 }
1141
1142 /**
1143 * Checks if the socket's output stream is shutdown
1144 *
1145 * @since 1.4
1146 */
1147 public boolean isOutputShutdown ()
1148 {
1149 return outputShutdown;
1150 }
1151 }