1 /* Copyright (C) 2003, 2004, 2005 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
16 #include <gnu/java/net/PlainSocketImpl.h>
17 #include <gnu/java/net/PlainSocketImpl$SocketInputStream.h>
18 #include <gnu/java/net/PlainSocketImpl$SocketOutputStream.h>
19 #include <java/io/IOException.h>
20 #include <java/net/BindException.h>
21 #include <java/net/ConnectException.h>
22 #include <java/net/InetAddress.h>
23 #include <java/net/InetSocketAddress.h>
24 #include <java/net/SocketException.h>
25 #include <java/net/SocketTimeoutException.h>
26 #include <java/lang/InternalError.h>
27 #include <java/lang/Object.h>
28 #include <java/lang/Boolean.h>
29 #include <java/lang/Class.h>
30 #include <java/lang/Integer.h>
31 #include <java/lang/Thread.h>
32 #include <java/lang/NullPointerException.h>
33 #include <java/lang/ArrayIndexOutOfBoundsException.h>
34 #include <java/lang/IllegalArgumentException.h>
38 struct sockaddr_in address
;
40 struct sockaddr_in6 address6
;
45 gnu::java::net::PlainSocketImpl::create (jboolean stream
)
47 SOCKET sock
= ::socket (AF_INET
, stream
? SOCK_STREAM
: SOCK_DGRAM
, 0);
49 if (sock
== INVALID_SOCKET
)
51 _Jv_ThrowIOException ();
54 // Cast this to a HANDLE so we can make
55 // it non-inheritable via _Jv_platform_close_on_exec.
56 HANDLE hSocket
= (HANDLE
) sock
;
57 _Jv_platform_close_on_exec (hSocket
);
59 // We use native_fd in place of fd here. From leaving fd null we avoid
60 // the double close problem in FileDescriptor.finalize.
61 native_fd
= (jint
) hSocket
;
65 gnu::java::net::PlainSocketImpl::bind (::java::net::InetAddress
*host
, jint lport
)
68 struct sockaddr
*ptr
= (struct sockaddr
*) &u
.address
;
69 jbyteArray haddress
= host
->addr
;
70 jbyte
*bytes
= elements (haddress
);
71 int len
= haddress
->length
;
75 u
.address
.sin_family
= AF_INET
;
78 memcpy (&u
.address
.sin_addr
, bytes
, len
);
80 u
.address
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
82 len
= sizeof (struct sockaddr_in
);
83 u
.address
.sin_port
= htons (lport
);
88 u
.address6
.sin6_family
= AF_INET6
;
89 memcpy (&u
.address6
.sin6_addr
, bytes
, len
);
90 len
= sizeof (struct sockaddr_in6
);
91 u
.address6
.sin6_port
= htons (lport
);
95 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
97 if (::bind (native_fd
, ptr
, len
) != SOCKET_ERROR
)
99 socklen_t addrlen
= sizeof(u
);
103 else if (::getsockname (native_fd
, (sockaddr
*) &u
, &addrlen
) != SOCKET_ERROR
)
104 localport
= ntohs (u
.address
.sin_port
);
112 DWORD dwErrorCode
= WSAGetLastError ();
113 throw new ::java::net::BindException (_Jv_WinStrError (dwErrorCode
));
117 throwConnectException (DWORD dwErrorCode
)
119 throw new ::java::net::ConnectException (_Jv_WinStrError (dwErrorCode
));
123 throwConnectException ()
125 throwConnectException (WSAGetLastError ());
129 gnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress
*addr
,
132 ::java::net::InetSocketAddress
*tmp
= (::java::net::InetSocketAddress
*) addr
;
133 ::java::net::InetAddress
*host
= tmp
->getAddress();
134 jint rport
= tmp
->getPort();
136 // Set the SocketImpl's address and port fields before we try to
137 // connect. Note that the fact that these are set doesn't imply
138 // that we're actually connected to anything. We need to record
139 // this data before we attempt the connect, since non-blocking
140 // SocketChannels will use this and almost certainly throw timeout
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
;
154 u
.address
.sin_family
= AF_INET
;
155 memcpy (&u
.address
.sin_addr
, bytes
, len
);
156 len
= sizeof (struct sockaddr_in
);
157 u
.address
.sin_port
= htons (rport
);
162 u
.address6
.sin6_family
= AF_INET6
;
163 memcpy (&u
.address6
.sin6_addr
, bytes
, len
);
164 len
= sizeof (struct sockaddr_in6
);
165 u
.address6
.sin6_port
= htons (rport
);
169 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
173 // FIXME: we're creating a fresh WSAEVENT for each connect().
174 WSAEventWrapper
aWSAEventWrapper(native_fd
, FD_CONNECT
);
175 WSAEVENT hEvent
= aWSAEventWrapper
.getEventHandle ();
177 if (::connect (native_fd
, ptr
, len
) == SOCKET_ERROR
)
179 if (WSAGetLastError () != WSAEWOULDBLOCK
)
180 throwConnectException ();
183 WSAWaitForMultipleEvents (1, &hEvent
, true, timeout
, false);
184 // use true, false instead of TRUE, FALSE because the
185 // MS constants got undefined
187 // Reset and ignore our thread's interrupted flag.
188 // It's not possible to interrupt these sort of
189 // operations on Win32 anyway.
190 ::java::lang::Thread::interrupted();
192 if (dwRet
== WSA_WAIT_FAILED
)
193 throwConnectException ();
194 else if (dwRet
== WSA_WAIT_TIMEOUT
)
195 throw new ::java::net::SocketTimeoutException
196 (JvNewStringUTF ("connect timed out"));
198 // If we get here, we still need to check whether the actual
199 // connect() succeeded. Use any socket-specific error code
200 // instead of the thread-based one.
201 int nErrCode
; int nErrLen
=sizeof(nErrCode
);
202 if (::getsockopt(native_fd
, SOL_SOCKET
, SO_ERROR
, (char*) &nErrCode
,
203 &nErrLen
) == SOCKET_ERROR
)
205 throwConnectException ();
208 if (nErrCode
!= NO_ERROR
)
210 throwConnectException (nErrCode
);
216 if (::connect (native_fd
, ptr
, len
) == SOCKET_ERROR
)
217 throwConnectException();
220 // A bind may not have been done on this socket; if so, set localport now.
223 if (::getsockname (native_fd
, (sockaddr
*) &u
, &addrlen
) != SOCKET_ERROR
)
224 localport
= ntohs (u
.address
.sin_port
);
226 throwConnectException();
231 gnu::java::net::PlainSocketImpl::listen (jint backlog
)
233 if (::listen (native_fd
, backlog
) == SOCKET_ERROR
)
235 _Jv_ThrowIOException ();
240 gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl
*s
)
243 socklen_t addrlen
= sizeof(u
);
245 SOCKET new_socket
= 0;
249 // FIXME: we're creating a fresh WSAEVENT for each accept().
250 // One possible alternative would be that native_fd really points
251 // to an extended structure consisting of the SOCKET, its
252 // associated WSAEVENT, etc.
253 WSAEventWrapper
aWSAEventWrapper(native_fd
, FD_ACCEPT
);
254 WSAEVENT hEvent
= aWSAEventWrapper
.getEventHandle ();
258 new_socket
= ::accept (native_fd
, (sockaddr
*) &u
, &addrlen
);
260 if (new_socket
!= INVALID_SOCKET
)
262 // This new child socket is nonblocking because the parent
263 // socket became nonblocking via the WSAEventSelect() call,
264 // so we set its mode back to blocking.
265 WSAEventSelect (new_socket
, hEvent
, 0);
266 // undo the hEvent <-> FD_ACCEPT association inherited
267 // inherited from our parent socket
269 unsigned long lSockOpt
= 0L;
271 if (ioctlsocket(new_socket
, FIONBIO
, &lSockOpt
) == SOCKET_ERROR
)
277 else if (WSAGetLastError () != WSAEWOULDBLOCK
)
283 WSAWaitForMultipleEvents (1, &hEvent
, true, timeout
, false);
284 // use true, false instead of TRUE, FALSE because the
285 // MS constants got undefined
287 // Reset and ignore our thread's interrupted flag.
288 ::java::lang::Thread::interrupted();
290 if (dwRet
== WSA_WAIT_FAILED
)
292 else if (dwRet
== WSA_WAIT_TIMEOUT
)
293 throw new ::java::net::SocketTimeoutException
294 (JvNewStringUTF ("Accept timed out"));
299 new_socket
= ::accept (native_fd
, (sockaddr
*) &u
, &addrlen
);
302 if (new_socket
== INVALID_SOCKET
)
305 // Cast this to a HANDLE so we can make
306 // it non-inheritable via _Jv_platform_close_on_exec.
307 hSocket
= (HANDLE
) new_socket
;
308 _Jv_platform_close_on_exec (hSocket
);
312 if (u
.address
.sin_family
== AF_INET
)
314 raddr
= JvNewByteArray (4);
315 memcpy (elements (raddr
), &u
.address
.sin_addr
, 4);
316 rport
= ntohs (u
.address
.sin_port
);
319 else if (u
.address
.sin_family
== AF_INET6
)
321 raddr
= JvNewByteArray (16);
322 memcpy (elements (raddr
), &u
.address6
.sin6_addr
, 16);
323 rport
= ntohs (u
.address6
.sin6_port
);
327 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
329 s
->native_fd
= (jint
) hSocket
;
330 s
->localport
= localport
;
331 s
->address
= new ::java::net::InetAddress (raddr
, NULL
);
336 _Jv_ThrowIOException ();
339 // Close(shutdown) the socket.
341 gnu::java::net::PlainSocketImpl::close()
343 // Avoid races from asynchronous finalization.
344 JvSynchronize
sync (this);
346 // should we use shutdown here? how would that effect so_linger?
347 int res
= ::closesocket (native_fd
);
351 // These three errors are not errors according to tests performed
352 // on the reference implementation.
353 DWORD dwErr
= WSAGetLastError();
354 if (dwErr
!= WSAENOTCONN
&& dwErr
!= WSAECONNRESET
355 && dwErr
!= WSAENOTSOCK
)
356 _Jv_ThrowIOException ();
358 // Safe place to reset the file pointer.
363 // Write a byte to the socket.
365 gnu::java::net::PlainSocketImpl$
SocketOutputStream::write(jint b
)
372 r
= ::send (this$
0->native_fd
, (char*) &d
, 1, 0);
375 DWORD dwErr
= WSAGetLastError();
377 // Reset and ignore our thread's interrupted flag.
378 // It's not possible to interrupt these sort of
379 // operations on Win32 anyway.
380 ::java::lang::Thread::interrupted();
382 // Some errors should not cause exceptions.
383 if (dwErr
!= WSAENOTCONN
&& dwErr
!= WSAECONNRESET
384 && dwErr
!= WSAENOTSOCK
)
385 _Jv_ThrowIOException ();
391 // Write some bytes to the socket.
393 gnu::java::net::PlainSocketImpl$
SocketOutputStream::write(jbyteArray b
,
394 jint offset
, jint len
)
397 throw new ::java::lang::NullPointerException
;
398 if (offset
< 0 || len
< 0 || offset
+ len
> JvGetArrayLength (b
))
399 throw new ::java::lang::ArrayIndexOutOfBoundsException
;
401 jbyte
*bytes
= elements (b
) + offset
;
405 int r
= ::send (this$
0->native_fd
, (char*) bytes
, len
, 0);
409 DWORD dwErr
= WSAGetLastError();
411 // Reset and ignore our thread's interrupted flag.
412 ::java::lang::Thread::interrupted();
414 // Some errors should not cause exceptions.
415 if (dwErr
!= WSAENOTCONN
&& dwErr
!= WSAECONNRESET
416 && dwErr
!= WSAENOTSOCK
)
417 _Jv_ThrowIOException ();
428 gnu::java::net::PlainSocketImpl::sendUrgentData (jint
)
430 throw new ::java::net::SocketException (JvNewStringLatin1 (
431 "PlainSocketImpl: sending of urgent data not supported by this socket"));
436 doRead(int native_fd
, void* buf
, int count
, int timeout
)
439 DWORD dwErrorCode
= 0;
440 // we are forced to declare this here because
441 // a call to Thread::interrupted() blanks out
442 // WSAGetLastError().
444 // FIXME: we unconditionally set SO_RCVTIMEO here
445 // because we can't detect whether someone has
446 // gone from a non-zero to zero timeout. What we'd
447 // really need is a member state variable in addition
449 int nRet
= ::setsockopt(native_fd
, SOL_SOCKET
, SO_RCVTIMEO
,
450 (char*)&timeout
, sizeof(timeout
));
451 if (nRet
!= NO_ERROR
)
453 dwErrorCode
= WSAGetLastError ();
457 r
= ::recv (native_fd
, (char*) buf
, count
, 0);
462 dwErrorCode
= WSAGetLastError ();
463 // save WSAGetLastError() before calling Thread.interrupted()
465 // Reset and ignore our thread's interrupted flag.
466 ::java::lang::Thread::interrupted();
471 // Some errors cause us to return end of stream...
472 if (dwErrorCode
== WSAENOTCONN
)
475 // Other errors need to be signalled.
476 if (dwErrorCode
== WSAETIMEDOUT
)
477 throw new ::java::net::SocketTimeoutException
478 (JvNewStringUTF ("Read timed out") );
480 _Jv_ThrowIOException (dwErrorCode
);
486 // Read a single byte from the socket.
488 gnu::java::net::PlainSocketImpl$
SocketInputStream::read(void)
491 doRead(this$
0->native_fd
, &b
, 1, this$
0->timeout
);
495 // Read count bytes into the buffer, starting at offset.
497 gnu::java::net::PlainSocketImpl$
SocketInputStream::read(jbyteArray buffer
,
498 jint offset
, jint count
)
500 // If zero bytes were requested, short circuit so that recv
501 // doesn't signal EOF.
506 throw new ::java::lang::NullPointerException
;
508 jsize bsize
= JvGetArrayLength (buffer
);
510 if (offset
< 0 || count
< 0 || offset
+ count
> bsize
)
511 throw new ::java::lang::ArrayIndexOutOfBoundsException
;
513 jbyte
*bytes
= elements (buffer
) + offset
;
516 return doRead(this$
0->native_fd
, bytes
, count
, this$
0->timeout
);
519 // How many bytes are available?
521 gnu::java::net::PlainSocketImpl::available(void)
523 unsigned long num
= 0;
525 if (::ioctlsocket (native_fd
, FIONREAD
, &num
) == SOCKET_ERROR
)
526 _Jv_ThrowIOException ();
532 gnu::java::net::PlainSocketImpl::setOption (jint optID
, ::java::lang::Object
*value
)
535 socklen_t val_len
= sizeof (val
);
538 throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
540 if (_Jv_IsInstanceOf (value
, &::java::lang::Boolean::class$
))
542 ::java::lang::Boolean
*boolobj
=
543 static_cast< ::java::lang::Boolean
*> (value
);
544 if (boolobj
->booleanValue())
548 if (optID
== _Jv_SO_LINGER_
)
554 else if (_Jv_IsInstanceOf (value
, &::java::lang::Integer::class$
))
556 ::java::lang::Integer
*intobj
=
557 static_cast< ::java::lang::Integer
*> (value
);
558 val
= (int) intobj
->intValue();
562 throw new ::java::lang::IllegalArgumentException (
563 JvNewStringLatin1 ("`value' must be Boolean or Integer"));
568 case _Jv_TCP_NODELAY_
:
569 if (::setsockopt (native_fd
, IPPROTO_TCP
, TCP_NODELAY
, (char *) &val
,
570 val_len
) == SOCKET_ERROR
)
574 case _Jv_SO_KEEPALIVE_
:
575 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_KEEPALIVE
, (char *) &val
,
576 val_len
) == SOCKET_ERROR
)
580 case _Jv_SO_BROADCAST_
:
581 throw new ::java::net::SocketException
582 (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
585 case _Jv_SO_OOBINLINE_
:
586 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *) &val
,
587 val_len
) == SOCKET_ERROR
)
591 case _Jv_SO_LINGER_
:
593 l_val
.l_onoff
= (val
!= -1);
594 l_val
.l_linger
= val
;
596 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_LINGER
, (char *) &l_val
,
597 sizeof(l_val
)) == SOCKET_ERROR
)
601 case _Jv_SO_SNDBUF_
:
602 case _Jv_SO_RCVBUF_
:
604 optID
== _Jv_SO_SNDBUF_
? opt
= SO_SNDBUF
: opt
= SO_RCVBUF
;
605 if (::setsockopt (native_fd
, SOL_SOCKET
, opt
, (char *) &val
,
606 val_len
) == SOCKET_ERROR
)
610 case _Jv_SO_BINDADDR_
:
611 throw new ::java::net::SocketException (
612 JvNewStringUTF ("SO_BINDADDR: read only option"));
615 case _Jv_IP_MULTICAST_IF_
:
616 throw new ::java::net::SocketException (
617 JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
620 case _Jv_IP_MULTICAST_IF2_
:
621 throw new ::java::net::SocketException (
622 JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
625 case _Jv_IP_MULTICAST_LOOP_
:
626 throw new ::java::net::SocketException (
627 JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
631 if (::setsockopt (native_fd
, SOL_SOCKET
, IP_TOS
, (char *) &val
,
632 val_len
) == SOCKET_ERROR
)
636 case _Jv_SO_REUSEADDR_
:
637 throw new ::java::net::SocketException (
638 JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
641 case _Jv_SO_TIMEOUT_
:
646 WSASetLastError (WSAENOPROTOOPT
);
650 _Jv_ThrowSocketException ();
653 ::java::lang::Object
*
654 gnu::java::net::PlainSocketImpl::getOption (jint optID
)
657 socklen_t val_len
= sizeof(val
);
659 socklen_t addrlen
= sizeof(u
);
661 socklen_t l_val_len
= sizeof(l_val
);
665 case _Jv_TCP_NODELAY_
:
666 if (::getsockopt (native_fd
, IPPROTO_TCP
, TCP_NODELAY
, (char *) &val
,
667 &val_len
) == SOCKET_ERROR
)
670 return new ::java::lang::Boolean (val
!= 0);
673 case _Jv_SO_LINGER_
:
674 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_LINGER
, (char *) &l_val
,
675 &l_val_len
) == SOCKET_ERROR
)
679 return new ::java::lang::Integer (l_val
.l_linger
);
681 return new ::java::lang::Boolean ((jboolean
)false);
684 case _Jv_SO_KEEPALIVE_
:
685 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_KEEPALIVE
, (char *) &val
,
686 &val_len
) == SOCKET_ERROR
)
689 return new ::java::lang::Boolean (val
!= 0);
691 case _Jv_SO_BROADCAST_
:
692 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_BROADCAST
, (char *) &val
,
693 &val_len
) == SOCKET_ERROR
)
695 return new ::java::lang::Boolean ((jboolean
)val
);
697 case _Jv_SO_OOBINLINE_
:
698 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *) &val
,
699 &val_len
) == SOCKET_ERROR
)
701 return new ::java::lang::Boolean ((jboolean
)val
);
703 case _Jv_SO_RCVBUF_
:
704 case _Jv_SO_SNDBUF_
:
706 optID
== _Jv_SO_SNDBUF_
? opt
= SO_SNDBUF
: opt
= SO_RCVBUF
;
707 if (::getsockopt (native_fd
, SOL_SOCKET
, opt
, (char *) &val
,
708 &val_len
) == SOCKET_ERROR
)
711 return new ::java::lang::Integer (val
);
713 case _Jv_SO_BINDADDR_
:
714 // cache the local address
715 if (localAddress
== NULL
)
719 if (::getsockname (native_fd
, (sockaddr
*) &u
,
720 &addrlen
) == SOCKET_ERROR
)
723 if (u
.address
.sin_family
== AF_INET
)
725 laddr
= JvNewByteArray (4);
726 memcpy (elements (laddr
), &u
.address
.sin_addr
, 4);
729 else if (u
.address
.sin_family
== AF_INET6
)
731 laddr
= JvNewByteArray (16);
732 memcpy (elements (laddr
), &u
.address6
.sin6_addr
, 16);
736 throw new ::java::net::SocketException
737 (JvNewStringUTF ("invalid family"));
738 localAddress
= new ::java::net::InetAddress (laddr
, NULL
);
743 case _Jv_IP_MULTICAST_IF_
:
744 throw new ::java::net::SocketException
745 (JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
748 case _Jv_IP_MULTICAST_IF2_
:
749 throw new ::java::net::SocketException
750 (JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
753 case _Jv_IP_MULTICAST_LOOP_
:
754 throw new ::java::net::SocketException
755 (JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
759 if (::getsockopt (native_fd
, SOL_SOCKET
, IP_TOS
, (char *) &val
,
760 &val_len
) == SOCKET_ERROR
)
762 return new ::java::lang::Integer (val
);
765 case _Jv_SO_REUSEADDR_
:
766 throw new ::java::net::SocketException
767 (JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
770 case _Jv_SO_TIMEOUT_
:
771 return new ::java::lang::Integer (timeout
);
775 WSASetLastError (WSAENOPROTOOPT
);
779 _Jv_ThrowSocketException ();
781 // we should never get here
785 gnu::java::net::PlainSocketImpl::shutdownInput (void)
787 if (::shutdown (native_fd
, 0))
788 _Jv_ThrowSocketException ();
792 gnu::java::net::PlainSocketImpl::shutdownOutput (void)
794 if (::shutdown (native_fd
, 1))
795 _Jv_ThrowSocketException ();