1 /* Copyright (C) 2003, 2004 Free Software Foundation
3 This file is part of libgcj.
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
12 #ifdef HAVE_SYS_IOCTL_H
13 #define BSD_COMP /* Get FIONREAD on Solaris2. */
14 #include <sys/ioctl.h>
17 // Pick up FIONREAD on Solaris 2.5.
18 #ifdef HAVE_SYS_FILIO_H
19 #include <sys/filio.h>
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
28 // Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
33 #include <gcj/javaprims.h>
34 #include <gnu/java/net/PlainSocketImpl.h>
35 #include <gnu/java/net/PlainSocketImpl$SocketInputStream.h>
36 #include <gnu/java/net/PlainSocketImpl$SocketOutputStream.h>
37 #include <java/io/IOException.h>
38 #include <java/io/InterruptedIOException.h>
39 #include <java/net/BindException.h>
40 #include <java/net/ConnectException.h>
41 #include <java/net/InetAddress.h>
42 #include <java/net/InetSocketAddress.h>
43 #include <java/net/SocketException.h>
44 #include <java/net/SocketTimeoutException.h>
45 #include <java/lang/InternalError.h>
46 #include <java/lang/Object.h>
47 #include <java/lang/Boolean.h>
48 #include <java/lang/Class.h>
49 #include <java/lang/Integer.h>
50 #include <java/lang/Thread.h>
51 #include <java/lang/NullPointerException.h>
52 #include <java/lang/ArrayIndexOutOfBoundsException.h>
53 #include <java/lang/IllegalArgumentException.h>
57 struct sockaddr_in address
;
59 struct sockaddr_in6 address6
;
64 gnu::java::net::PlainSocketImpl::create (jboolean stream
)
66 int sock
= _Jv_socket (AF_INET
, stream
? SOCK_STREAM
: SOCK_DGRAM
, 0);
70 char* strerr
= strerror (errno
);
71 throw new ::java::io::IOException (JvNewStringUTF (strerr
));
74 _Jv_platform_close_on_exec (sock
);
76 // We use native_fd in place of fd here. From leaving fd null we avoid
77 // the double close problem in FileDescriptor.finalize.
82 gnu::java::net::PlainSocketImpl::bind (::java::net::InetAddress
*host
, jint lport
)
85 struct sockaddr
*ptr
= (struct sockaddr
*) &u
.address
;
86 jbyteArray haddress
= host
->addr
;
87 jbyte
*bytes
= elements (haddress
);
88 int len
= haddress
->length
;
93 u
.address
.sin_family
= AF_INET
;
96 memcpy (&u
.address
.sin_addr
, bytes
, len
);
98 u
.address
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
100 len
= sizeof (struct sockaddr_in
);
101 u
.address
.sin_port
= htons (lport
);
106 u
.address6
.sin6_family
= AF_INET6
;
107 memcpy (&u
.address6
.sin6_addr
, bytes
, len
);
108 len
= sizeof (struct sockaddr_in6
);
109 u
.address6
.sin6_port
= htons (lport
);
113 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
115 // Enable SO_REUSEADDR, so that servers can reuse ports left in TIME_WAIT.
116 ::setsockopt(native_fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &i
, sizeof(i
));
118 if (_Jv_bind (native_fd
, ptr
, len
) == 0)
120 socklen_t addrlen
= sizeof(u
);
124 else if (::getsockname (native_fd
, (sockaddr
*) &u
, &addrlen
) == 0)
125 localport
= ntohs (u
.address
.sin_port
);
133 char* strerr
= strerror (errno
);
134 throw new ::java::net::BindException (JvNewStringUTF (strerr
));
138 gnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress
*addr
,
141 ::java::net::InetSocketAddress
*tmp
= (::java::net::InetSocketAddress
*) addr
;
142 ::java::net::InetAddress
*host
= tmp
->getAddress();
143 jint rport
= tmp
->getPort();
146 socklen_t addrlen
= sizeof(u
);
147 jbyteArray haddress
= host
->addr
;
148 jbyte
*bytes
= elements (haddress
);
149 int len
= haddress
->length
;
150 struct sockaddr
*ptr
= (struct sockaddr
*) &u
.address
;
153 u
.address
.sin_family
= AF_INET
;
154 memcpy (&u
.address
.sin_addr
, bytes
, len
);
155 len
= sizeof (struct sockaddr_in
);
156 u
.address
.sin_port
= htons (rport
);
161 u
.address6
.sin6_family
= AF_INET6
;
162 memcpy (&u
.address6
.sin6_addr
, bytes
, len
);
163 len
= sizeof (struct sockaddr_in6
);
164 u
.address6
.sin6_port
= htons (rport
);
168 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
172 int flags
= ::fcntl (native_fd
, F_GETFL
);
173 ::fcntl (native_fd
, F_SETFL
, flags
| O_NONBLOCK
);
175 if ((_Jv_connect (native_fd
, ptr
, len
) != 0) && (errno
!= EINPROGRESS
))
181 FD_SET(native_fd
, &fset
);
182 tv
.tv_sec
= timeout
/ 1000;
183 tv
.tv_usec
= (timeout
% 1000) * 1000;
186 if ((retval
= _Jv_select (native_fd
+ 1, &fset
, &fset
, NULL
, &tv
)) < 0)
188 else if (retval
== 0)
189 throw new ::java::net::SocketTimeoutException
190 (JvNewStringUTF ("Connect timed out"));
191 // Set the socket back into a blocking state.
192 ::fcntl (native_fd
, F_SETFL
, flags
);
196 if (_Jv_connect (native_fd
, ptr
, len
) != 0)
203 // A bind may not have been done on this socket; if so, set localport now.
206 if (::getsockname (native_fd
, (sockaddr
*) &u
, &addrlen
) == 0)
207 localport
= ntohs (u
.address
.sin_port
);
215 char* strerr
= strerror (errno
);
216 throw new ::java::net::ConnectException (JvNewStringUTF (strerr
));
220 gnu::java::net::PlainSocketImpl::listen (jint backlog
)
222 if (::listen (native_fd
, backlog
) != 0)
224 char* strerr
= strerror (errno
);
225 throw new ::java::io::IOException (JvNewStringUTF (strerr
));
230 gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl
*s
)
233 socklen_t addrlen
= sizeof(u
);
236 // Do timeouts via select since SO_RCVTIMEO is not always available.
237 if (timeout
> 0 && native_fd
>= 0 && native_fd
< FD_SETSIZE
)
242 FD_SET(native_fd
, &fset
);
243 tv
.tv_sec
= timeout
/ 1000;
244 tv
.tv_usec
= (timeout
% 1000) * 1000;
246 if ((retval
= _Jv_select (native_fd
+ 1, &fset
, &fset
, NULL
, &tv
)) < 0)
248 else if (retval
== 0)
249 throw new ::java::net::SocketTimeoutException (
250 JvNewStringUTF("Accept timed out"));
253 new_socket
= _Jv_accept (native_fd
, (sockaddr
*) &u
, &addrlen
);
258 _Jv_platform_close_on_exec (new_socket
);
262 if (u
.address
.sin_family
== AF_INET
)
264 raddr
= JvNewByteArray (4);
265 memcpy (elements (raddr
), &u
.address
.sin_addr
, 4);
266 rport
= ntohs (u
.address
.sin_port
);
269 else if (u
.address
.sin_family
== AF_INET6
)
271 raddr
= JvNewByteArray (16);
272 memcpy (elements (raddr
), &u
.address6
.sin6_addr
, 16);
273 rport
= ntohs (u
.address6
.sin6_port
);
277 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
279 s
->native_fd
= new_socket
;
280 s
->localport
= localport
;
281 s
->address
= new ::java::net::InetAddress (raddr
, NULL
);
286 char* strerr
= strerror (errno
);
287 throw new ::java::io::IOException (JvNewStringUTF (strerr
));
290 // Close(shutdown) the socket.
292 gnu::java::net::PlainSocketImpl::close()
294 // Avoid races from asynchronous finalization.
295 JvSynchronize
sync (this);
297 // should we use shutdown here? how would that effect so_linger?
298 int res
= _Jv_close (native_fd
);
302 // These three errors are not errors according to tests performed
303 // on the reference implementation.
304 if (errno
!= ENOTCONN
&& errno
!= ECONNRESET
&& errno
!= EBADF
)
305 throw new ::java::io::IOException (JvNewStringUTF (strerror (errno
)));
307 // Safe place to reset the file pointer.
313 write_helper (jint native_fd
, jbyte
*bytes
, jint len
);
315 // Write a byte to the socket.
317 gnu::java::net::PlainSocketImpl$
SocketOutputStream::write(jint b
)
319 jbyte data
= (jbyte
) b
;
320 write_helper (this$
0->native_fd
, &data
, 1);
323 // Write some bytes to the socket.
325 gnu::java::net::PlainSocketImpl$
SocketOutputStream::write(jbyteArray b
, jint offset
, jint len
)
328 throw new ::java::lang::NullPointerException
;
329 if (offset
< 0 || len
< 0 || offset
+ len
> JvGetArrayLength (b
))
330 throw new ::java::lang::ArrayIndexOutOfBoundsException
;
332 write_helper (this$
0->native_fd
, elements (b
) + offset
* sizeof (jbyte
), len
);
336 write_helper(jint native_fd
, jbyte
*bytes
, jint len
)
342 int r
= _Jv_write (native_fd
, bytes
, len
);
346 if (::java::lang::Thread::interrupted())
348 ::java::io::InterruptedIOException
*iioe
349 = new ::java::io::InterruptedIOException
350 (JvNewStringLatin1 (strerror (errno
)));
351 iioe
->bytesTransferred
= written
;
354 // Some errors should not cause exceptions.
355 if (errno
!= ENOTCONN
&& errno
!= ECONNRESET
&& errno
!= EBADF
)
356 throw new ::java::io::IOException (JvNewStringUTF (strerror (errno
)));
367 gnu::java::net::PlainSocketImpl::sendUrgentData (jint
)
369 throw new ::java::net::SocketException (JvNewStringLatin1 (
370 "PlainSocketImpl: sending of urgent data not supported by this socket"));
374 read_helper (jint native_fd
, jint timeout
, jbyte
*bytes
, jint count
);
376 // Read a single byte from the socket.
378 gnu::java::net::PlainSocketImpl$
SocketInputStream::read(void)
382 if (read_helper (this$
0->native_fd
, this$
0->timeout
, &data
, 1) == 1)
388 // Read count bytes into the buffer, starting at offset.
390 gnu::java::net::PlainSocketImpl$
SocketInputStream::read(jbyteArray buffer
, jint offset
,
394 throw new ::java::lang::NullPointerException
;
396 jsize bsize
= JvGetArrayLength (buffer
);
398 if (offset
< 0 || count
< 0 || offset
+ count
> bsize
)
399 throw new ::java::lang::ArrayIndexOutOfBoundsException
;
401 return read_helper (this$
0->native_fd
, this$
0->timeout
,
402 elements (buffer
) + offset
* sizeof (jbyte
), count
);
406 read_helper (jint native_fd
, jint timeout
, jbyte
*bytes
, jint count
)
408 // Do timeouts via select.
409 if (timeout
> 0 && native_fd
>= 0 && native_fd
< FD_SETSIZE
)
411 // Create the file descriptor set.
414 FD_SET (native_fd
, &read_fds
);
415 // Create the timeout struct based on our internal timeout value.
416 struct timeval timeout_value
;
417 timeout_value
.tv_sec
= timeout
/ 1000;
418 timeout_value
.tv_usec
=(timeout
% 1000) * 1000;
419 // Select on the fds.
421 _Jv_select (native_fd
+ 1, &read_fds
, NULL
, NULL
, &timeout_value
);
422 // We're only interested in the 0 return.
423 // error returns still require us to try to read
424 // the socket to see what happened.
427 ::java::net::SocketTimeoutException
*timeoutException
=
428 new ::java::net::SocketTimeoutException
429 (JvNewStringUTF ("Read timed out"));
430 throw timeoutException
;
435 int r
= ::recv (native_fd
, (char *) bytes
, count
, 0);
440 if (::java::lang::Thread::interrupted())
442 ::java::io::InterruptedIOException
*iioe
=
443 new ::java::io::InterruptedIOException
444 (JvNewStringUTF ("Read interrupted"));
445 iioe
->bytesTransferred
= r
== -1 ? 0 : r
;
450 // Some errors cause us to return end of stream...
451 if (errno
== ENOTCONN
)
454 // Other errors need to be signalled.
455 throw new ::java::io::IOException (JvNewStringUTF (strerror (errno
)));
461 // How many bytes are available?
463 gnu::java::net::PlainSocketImpl::available(void)
465 #if defined(FIONREAD) || defined(HAVE_SELECT)
468 bool num_set
= false;
470 #if defined(FIONREAD)
471 r
= ::ioctl (native_fd
, FIONREAD
, &num
);
473 if (r
== -1 && errno
== ENOTTY
)
475 // If the ioctl doesn't work, we don't care.
481 #elif defined(HAVE_SELECT)
492 throw new ::java::io::IOException(JvNewStringUTF(strerror(errno
)));
495 // If we didn't get anything we can use select.
497 #if defined(HAVE_SELECT)
499 if (! num_set
&& native_fd
>= 0 && native_fd
< FD_SETSIZE
)
503 FD_SET (native_fd
, &rd
);
507 r
= _Jv_select (native_fd
+ 1, &rd
, NULL
, NULL
, &tv
);
510 num
= r
== 0 ? 0 : 1;
512 #endif /* HAVE_SELECT */
516 throw new ::java::io::IOException (JvNewStringUTF ("unimplemented"));
521 gnu::java::net::PlainSocketImpl::setOption (jint optID
, ::java::lang::Object
*value
)
524 socklen_t val_len
= sizeof (val
);
527 throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
529 if (_Jv_IsInstanceOf (value
, &::java::lang::Boolean::class$
))
531 ::java::lang::Boolean
*boolobj
=
532 static_cast< ::java::lang::Boolean
*> (value
);
533 if (boolobj
->booleanValue())
537 if (optID
== _Jv_SO_LINGER_
)
543 else if (_Jv_IsInstanceOf (value
, &::java::lang::Integer::class$
))
545 ::java::lang::Integer
*intobj
=
546 static_cast< ::java::lang::Integer
*> (value
);
547 val
= (int) intobj
->intValue();
551 throw new ::java::lang::IllegalArgumentException (
552 JvNewStringLatin1 ("`value' must be Boolean or Integer"));
557 case _Jv_TCP_NODELAY_
:
559 if (::setsockopt (native_fd
, IPPROTO_TCP
, TCP_NODELAY
, (char *) &val
,
563 throw new ::java::lang::InternalError
564 (JvNewStringUTF ("TCP_NODELAY not supported"));
565 #endif /* TCP_NODELAY */
568 case _Jv_SO_KEEPALIVE_
:
569 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_KEEPALIVE
, (char *) &val
,
574 case _Jv_SO_BROADCAST_
:
575 throw new ::java::net::SocketException
576 (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
579 case _Jv_SO_OOBINLINE_
:
580 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *) &val
,
585 case _Jv_SO_LINGER_
:
588 l_val
.l_onoff
= (val
!= -1);
589 l_val
.l_linger
= val
;
591 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_LINGER
, (char *) &l_val
,
595 throw new ::java::lang::InternalError (
596 JvNewStringUTF ("SO_LINGER not supported"));
597 #endif /* SO_LINGER */
600 case _Jv_SO_SNDBUF_
:
601 case _Jv_SO_RCVBUF_
:
602 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
604 optID
== _Jv_SO_SNDBUF_
? opt
= SO_SNDBUF
: opt
= SO_RCVBUF
;
605 if (::setsockopt (native_fd
, SOL_SOCKET
, opt
, (char *) &val
, val_len
) != 0)
608 throw new ::java::lang::InternalError (
609 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
613 case _Jv_SO_BINDADDR_
:
614 throw new ::java::net::SocketException (
615 JvNewStringUTF ("SO_BINDADDR: read only option"));
618 case _Jv_IP_MULTICAST_IF_
:
619 throw new ::java::net::SocketException (
620 JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
623 case _Jv_IP_MULTICAST_IF2_
:
624 throw new ::java::net::SocketException (
625 JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
628 case _Jv_IP_MULTICAST_LOOP_
:
629 throw new ::java::net::SocketException (
630 JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
634 if (::setsockopt (native_fd
, SOL_SOCKET
, IP_TOS
, (char *) &val
,
639 case _Jv_SO_REUSEADDR_
:
640 #if defined(SO_REUSEADDR)
641 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &val
,
645 throw new ::java::lang::InternalError (
646 JvNewStringUTF ("SO_REUSEADDR not supported"));
649 case _Jv_SO_TIMEOUT_
:
658 char* strerr
= strerror (errno
);
659 throw new ::java::net::SocketException (JvNewStringUTF (strerr
));
662 ::java::lang::Object
*
663 gnu::java::net::PlainSocketImpl::getOption (jint optID
)
666 socklen_t val_len
= sizeof(val
);
668 socklen_t addrlen
= sizeof(u
);
670 socklen_t l_val_len
= sizeof(l_val
);
675 case _Jv_TCP_NODELAY_
:
676 if (::getsockopt (native_fd
, IPPROTO_TCP
, TCP_NODELAY
, (char *) &val
,
680 return new ::java::lang::Boolean (val
!= 0);
682 throw new ::java::lang::InternalError
683 (JvNewStringUTF ("TCP_NODELAY not supported"));
687 case _Jv_SO_LINGER_
:
689 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_LINGER
, (char *) &l_val
,
694 return new ::java::lang::Integer (l_val
.l_linger
);
696 return new ::java::lang::Boolean ((jboolean
)false);
698 throw new ::java::lang::InternalError
699 (JvNewStringUTF ("SO_LINGER not supported"));
703 case _Jv_SO_KEEPALIVE_
:
704 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_KEEPALIVE
, (char *) &val
,
708 return new ::java::lang::Boolean (val
!= 0);
710 case _Jv_SO_BROADCAST_
:
711 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_BROADCAST
, (char *) &val
,
714 return new ::java::lang::Boolean ((jboolean
)val
);
716 case _Jv_SO_OOBINLINE_
:
717 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *) &val
,
720 return new ::java::lang::Boolean ((jboolean
)val
);
722 case _Jv_SO_RCVBUF_
:
723 case _Jv_SO_SNDBUF_
:
724 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
726 optID
== _Jv_SO_SNDBUF_
? opt
= SO_SNDBUF
: opt
= SO_RCVBUF
;
727 if (::getsockopt (native_fd
, SOL_SOCKET
, opt
, (char *) &val
, &val_len
) != 0)
730 return new ::java::lang::Integer (val
);
732 throw new ::java::lang::InternalError
733 (JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
736 case _Jv_SO_BINDADDR_
:
737 // cache the local address
738 if (localAddress
== NULL
)
742 if (::getsockname (native_fd
, (sockaddr
*) &u
, &addrlen
) != 0)
745 if (u
.address
.sin_family
== AF_INET
)
747 laddr
= JvNewByteArray (4);
748 memcpy (elements (laddr
), &u
.address
.sin_addr
, 4);
751 else if (u
.address
.sin_family
== AF_INET6
)
753 laddr
= JvNewByteArray (16);
754 memcpy (elements (laddr
), &u
.address6
.sin6_addr
, 16);
758 throw new ::java::net::SocketException
759 (JvNewStringUTF ("invalid family"));
760 localAddress
= new ::java::net::InetAddress (laddr
, NULL
);
765 case _Jv_IP_MULTICAST_IF_
:
766 throw new ::java::net::SocketException
767 (JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
770 case _Jv_IP_MULTICAST_IF2_
:
771 throw new ::java::net::SocketException
772 (JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
775 case _Jv_IP_MULTICAST_LOOP_
:
776 throw new ::java::net::SocketException
777 (JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
781 if (::getsockopt (native_fd
, SOL_SOCKET
, IP_TOS
, (char *) &val
,
784 return new ::java::lang::Integer (val
);
787 case _Jv_SO_REUSEADDR_
:
788 #if defined(SO_REUSEADDR)
789 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &val
,
793 throw new ::java::lang::InternalError (
794 JvNewStringUTF ("SO_REUSEADDR not supported"));
798 case _Jv_SO_TIMEOUT_
:
799 return new ::java::lang::Integer (timeout
);
807 char* strerr
= strerror (errno
);
808 throw new ::java::net::SocketException (JvNewStringUTF (strerr
));
812 gnu::java::net::PlainSocketImpl::shutdownInput (void)
814 if (::shutdown (native_fd
, 0))
815 throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno
)));
819 gnu::java::net::PlainSocketImpl::shutdownOutput (void)
821 if (::shutdown (native_fd
, 1))
822 throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno
)));