1 /* Copyright (C) 2003 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();
137 socklen_t addrlen
= sizeof(u
);
138 jbyteArray haddress
= host
->addr
;
139 jbyte
*bytes
= elements (haddress
);
140 int len
= haddress
->length
;
141 struct sockaddr
*ptr
= (struct sockaddr
*) &u
.address
;
145 u
.address
.sin_family
= AF_INET
;
146 memcpy (&u
.address
.sin_addr
, bytes
, len
);
147 len
= sizeof (struct sockaddr_in
);
148 u
.address
.sin_port
= htons (rport
);
153 u
.address6
.sin6_family
= AF_INET6
;
154 memcpy (&u
.address6
.sin6_addr
, bytes
, len
);
155 len
= sizeof (struct sockaddr_in6
);
156 u
.address6
.sin6_port
= htons (rport
);
160 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
164 // FIXME: we're creating a fresh WSAEVENT for each connect().
165 WSAEventWrapper
aWSAEventWrapper(native_fd
, FD_CONNECT
);
166 WSAEVENT hEvent
= aWSAEventWrapper
.getEventHandle ();
168 if (::connect (native_fd
, ptr
, len
) == SOCKET_ERROR
)
170 if (WSAGetLastError () != WSAEWOULDBLOCK
)
171 throwConnectException ();
174 WSAWaitForMultipleEvents (1, &hEvent
, true, timeout
, false);
175 // use true, false instead of TRUE, FALSE because the
176 // MS constants got undefined
178 // Reset and ignore our thread's interrupted flag.
179 // It's not possible to interrupt these sort of
180 // operations on Win32 anyway.
181 ::java::lang::Thread::interrupted();
183 if (dwRet
== WSA_WAIT_FAILED
)
184 throwConnectException ();
185 else if (dwRet
== WSA_WAIT_TIMEOUT
)
186 throw new ::java::net::SocketTimeoutException
187 (JvNewStringUTF ("connect timed out"));
189 // If we get here, we still need to check whether the actual
190 // connect() succeeded. Use any socket-specific error code
191 // instead of the thread-based one.
192 int nErrCode
; int nErrLen
=sizeof(nErrCode
);
193 if (::getsockopt(native_fd
, SOL_SOCKET
, SO_ERROR
, (char*) &nErrCode
,
194 &nErrLen
) == SOCKET_ERROR
)
196 throwConnectException ();
199 if (nErrCode
!= NO_ERROR
)
201 throwConnectException (nErrCode
);
207 if (::connect (native_fd
, ptr
, len
) == SOCKET_ERROR
)
208 throwConnectException();
214 // A bind may not have been done on this socket; if so, set localport now.
217 if (::getsockname (native_fd
, (sockaddr
*) &u
, &addrlen
) != SOCKET_ERROR
)
218 localport
= ntohs (u
.address
.sin_port
);
220 throwConnectException();
225 gnu::java::net::PlainSocketImpl::listen (jint backlog
)
227 if (::listen (native_fd
, backlog
) == SOCKET_ERROR
)
229 _Jv_ThrowIOException ();
234 gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl
*s
)
237 socklen_t addrlen
= sizeof(u
);
239 SOCKET new_socket
= 0;
243 // FIXME: we're creating a fresh WSAEVENT for each accept().
244 // One possible alternative would be that native_fd really points
245 // to an extended structure consisting of the SOCKET, its
246 // associated WSAEVENT, etc.
247 WSAEventWrapper
aWSAEventWrapper(native_fd
, FD_ACCEPT
);
248 WSAEVENT hEvent
= aWSAEventWrapper
.getEventHandle ();
252 new_socket
= ::accept (native_fd
, (sockaddr
*) &u
, &addrlen
);
254 if (new_socket
!= INVALID_SOCKET
)
256 // This new child socket is nonblocking because the parent
257 // socket became nonblocking via the WSAEventSelect() call,
258 // so we set its mode back to blocking.
259 WSAEventSelect (new_socket
, hEvent
, 0);
260 // undo the hEvent <-> FD_ACCEPT association inherited
261 // inherited from our parent socket
263 unsigned long lSockOpt
= 0L;
265 if (ioctlsocket(new_socket
, FIONBIO
, &lSockOpt
) == SOCKET_ERROR
)
271 else if (WSAGetLastError () != WSAEWOULDBLOCK
)
277 WSAWaitForMultipleEvents (1, &hEvent
, true, timeout
, false);
278 // use true, false instead of TRUE, FALSE because the
279 // MS constants got undefined
281 // Reset and ignore our thread's interrupted flag.
282 ::java::lang::Thread::interrupted();
284 if (dwRet
== WSA_WAIT_FAILED
)
286 else if (dwRet
== WSA_WAIT_TIMEOUT
)
287 throw new ::java::net::SocketTimeoutException
288 (JvNewStringUTF ("Accept timed out"));
293 new_socket
= ::accept (native_fd
, (sockaddr
*) &u
, &addrlen
);
296 if (new_socket
== INVALID_SOCKET
)
299 // Cast this to a HANDLE so we can make
300 // it non-inheritable via _Jv_platform_close_on_exec.
301 hSocket
= (HANDLE
) new_socket
;
302 _Jv_platform_close_on_exec (hSocket
);
306 if (u
.address
.sin_family
== AF_INET
)
308 raddr
= JvNewByteArray (4);
309 memcpy (elements (raddr
), &u
.address
.sin_addr
, 4);
310 rport
= ntohs (u
.address
.sin_port
);
313 else if (u
.address
.sin_family
== AF_INET6
)
315 raddr
= JvNewByteArray (16);
316 memcpy (elements (raddr
), &u
.address6
.sin6_addr
, 16);
317 rport
= ntohs (u
.address6
.sin6_port
);
321 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
323 s
->native_fd
= (jint
) hSocket
;
324 s
->localport
= localport
;
325 s
->address
= new ::java::net::InetAddress (raddr
, NULL
);
330 _Jv_ThrowIOException ();
333 // Close(shutdown) the socket.
335 gnu::java::net::PlainSocketImpl::close()
337 // Avoid races from asynchronous finalization.
338 JvSynchronize
sync (this);
340 // should we use shutdown here? how would that effect so_linger?
341 int res
= ::closesocket (native_fd
);
345 // These three errors are not errors according to tests performed
346 // on the reference implementation.
347 DWORD dwErr
= WSAGetLastError();
348 if (dwErr
!= WSAENOTCONN
&& dwErr
!= WSAECONNRESET
349 && dwErr
!= WSAENOTSOCK
)
350 _Jv_ThrowIOException ();
352 // Safe place to reset the file pointer.
357 // Write a byte to the socket.
359 gnu::java::net::PlainSocketImpl$
SocketOutputStream::write(jint b
)
366 r
= ::send (this$
0->native_fd
, (char*) &d
, 1, 0);
369 DWORD dwErr
= WSAGetLastError();
371 // Reset and ignore our thread's interrupted flag.
372 // It's not possible to interrupt these sort of
373 // operations on Win32 anyway.
374 ::java::lang::Thread::interrupted();
376 // Some errors should not cause exceptions.
377 if (dwErr
!= WSAENOTCONN
&& dwErr
!= WSAECONNRESET
378 && dwErr
!= WSAENOTSOCK
)
379 _Jv_ThrowIOException ();
385 // Write some bytes to the socket.
387 gnu::java::net::PlainSocketImpl$
SocketOutputStream::write(jbyteArray b
,
388 jint offset
, jint len
)
391 throw new ::java::lang::NullPointerException
;
392 if (offset
< 0 || len
< 0 || offset
+ len
> JvGetArrayLength (b
))
393 throw new ::java::lang::ArrayIndexOutOfBoundsException
;
395 jbyte
*bytes
= elements (b
) + offset
;
399 int r
= ::send (this$
0->native_fd
, (char*) bytes
, len
, 0);
403 DWORD dwErr
= WSAGetLastError();
405 // Reset and ignore our thread's interrupted flag.
406 ::java::lang::Thread::interrupted();
408 // Some errors should not cause exceptions.
409 if (dwErr
!= WSAENOTCONN
&& dwErr
!= WSAECONNRESET
410 && dwErr
!= WSAENOTSOCK
)
411 _Jv_ThrowIOException ();
422 gnu::java::net::PlainSocketImpl::sendUrgentData (jint
)
424 throw new ::java::net::SocketException (JvNewStringLatin1 (
425 "PlainSocketImpl: sending of urgent data not supported by this socket"));
430 doRead(int native_fd
, void* buf
, int count
, int timeout
)
433 DWORD dwErrorCode
= 0;
434 // we are forced to declare this here because
435 // a call to Thread::interrupted() blanks out
436 // WSAGetLastError().
438 // FIXME: we unconditionally set SO_RCVTIMEO here
439 // because we can't detect whether someone has
440 // gone from a non-zero to zero timeout. What we'd
441 // really need is a member state variable in addition
443 int nRet
= ::setsockopt(native_fd
, SOL_SOCKET
, SO_RCVTIMEO
,
444 (char*)&timeout
, sizeof(timeout
));
445 if (nRet
!= NO_ERROR
)
447 dwErrorCode
= WSAGetLastError ();
451 r
= ::recv (native_fd
, (char*) buf
, count
, 0);
456 dwErrorCode
= WSAGetLastError ();
457 // save WSAGetLastError() before calling Thread.interrupted()
459 // Reset and ignore our thread's interrupted flag.
460 ::java::lang::Thread::interrupted();
465 // Some errors cause us to return end of stream...
466 if (dwErrorCode
== WSAENOTCONN
)
469 // Other errors need to be signalled.
470 if (dwErrorCode
== WSAETIMEDOUT
)
471 throw new ::java::net::SocketTimeoutException
472 (JvNewStringUTF ("Read timed out") );
474 _Jv_ThrowIOException (dwErrorCode
);
480 // Read a single byte from the socket.
482 gnu::java::net::PlainSocketImpl$
SocketInputStream::read(void)
485 doRead(this$
0->native_fd
, &b
, 1, this$
0->timeout
);
489 // Read count bytes into the buffer, starting at offset.
491 gnu::java::net::PlainSocketImpl$
SocketInputStream::read(jbyteArray buffer
,
492 jint offset
, jint count
)
495 throw new ::java::lang::NullPointerException
;
497 jsize bsize
= JvGetArrayLength (buffer
);
499 if (offset
< 0 || count
< 0 || offset
+ count
> bsize
)
500 throw new ::java::lang::ArrayIndexOutOfBoundsException
;
502 jbyte
*bytes
= elements (buffer
) + offset
;
505 return doRead(this$
0->native_fd
, bytes
, count
, this$
0->timeout
);
508 // How many bytes are available?
510 gnu::java::net::PlainSocketImpl::available(void)
512 unsigned long num
= 0;
514 if (::ioctlsocket (native_fd
, FIONREAD
, &num
) == SOCKET_ERROR
)
515 _Jv_ThrowIOException ();
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_
:
558 if (::setsockopt (native_fd
, IPPROTO_TCP
, TCP_NODELAY
, (char *) &val
,
559 val_len
) == SOCKET_ERROR
)
563 case _Jv_SO_KEEPALIVE_
:
564 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_KEEPALIVE
, (char *) &val
,
565 val_len
) == SOCKET_ERROR
)
569 case _Jv_SO_BROADCAST_
:
570 throw new ::java::net::SocketException
571 (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
574 case _Jv_SO_OOBINLINE_
:
575 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *) &val
,
576 val_len
) == SOCKET_ERROR
)
580 case _Jv_SO_LINGER_
:
582 l_val
.l_onoff
= (val
!= -1);
583 l_val
.l_linger
= val
;
585 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_LINGER
, (char *) &l_val
,
586 sizeof(l_val
)) == SOCKET_ERROR
)
590 case _Jv_SO_SNDBUF_
:
591 case _Jv_SO_RCVBUF_
:
593 optID
== _Jv_SO_SNDBUF_
? opt
= SO_SNDBUF
: opt
= SO_RCVBUF
;
594 if (::setsockopt (native_fd
, SOL_SOCKET
, opt
, (char *) &val
,
595 val_len
) == SOCKET_ERROR
)
599 case _Jv_SO_BINDADDR_
:
600 throw new ::java::net::SocketException (
601 JvNewStringUTF ("SO_BINDADDR: read only option"));
604 case _Jv_IP_MULTICAST_IF_
:
605 throw new ::java::net::SocketException (
606 JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
609 case _Jv_IP_MULTICAST_IF2_
:
610 throw new ::java::net::SocketException (
611 JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
614 case _Jv_IP_MULTICAST_LOOP_
:
615 throw new ::java::net::SocketException (
616 JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
620 if (::setsockopt (native_fd
, SOL_SOCKET
, IP_TOS
, (char *) &val
,
621 val_len
) == SOCKET_ERROR
)
625 case _Jv_SO_REUSEADDR_
:
626 throw new ::java::net::SocketException (
627 JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
630 case _Jv_SO_TIMEOUT_
:
635 WSASetLastError (WSAENOPROTOOPT
);
639 _Jv_ThrowSocketException ();
642 ::java::lang::Object
*
643 gnu::java::net::PlainSocketImpl::getOption (jint optID
)
646 socklen_t val_len
= sizeof(val
);
648 socklen_t addrlen
= sizeof(u
);
650 socklen_t l_val_len
= sizeof(l_val
);
654 case _Jv_TCP_NODELAY_
:
655 if (::getsockopt (native_fd
, IPPROTO_TCP
, TCP_NODELAY
, (char *) &val
,
656 &val_len
) == SOCKET_ERROR
)
659 return new ::java::lang::Boolean (val
!= 0);
662 case _Jv_SO_LINGER_
:
663 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_LINGER
, (char *) &l_val
,
664 &l_val_len
) == SOCKET_ERROR
)
668 return new ::java::lang::Integer (l_val
.l_linger
);
670 return new ::java::lang::Boolean ((jboolean
)false);
673 case _Jv_SO_KEEPALIVE_
:
674 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_KEEPALIVE
, (char *) &val
,
675 &val_len
) == SOCKET_ERROR
)
678 return new ::java::lang::Boolean (val
!= 0);
680 case _Jv_SO_BROADCAST_
:
681 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_BROADCAST
, (char *) &val
,
682 &val_len
) == SOCKET_ERROR
)
684 return new ::java::lang::Boolean ((jboolean
)val
);
686 case _Jv_SO_OOBINLINE_
:
687 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *) &val
,
688 &val_len
) == SOCKET_ERROR
)
690 return new ::java::lang::Boolean ((jboolean
)val
);
692 case _Jv_SO_RCVBUF_
:
693 case _Jv_SO_SNDBUF_
:
695 optID
== _Jv_SO_SNDBUF_
? opt
= SO_SNDBUF
: opt
= SO_RCVBUF
;
696 if (::getsockopt (native_fd
, SOL_SOCKET
, opt
, (char *) &val
,
697 &val_len
) == SOCKET_ERROR
)
700 return new ::java::lang::Integer (val
);
702 case _Jv_SO_BINDADDR_
:
703 // cache the local address
704 if (localAddress
== NULL
)
708 if (::getsockname (native_fd
, (sockaddr
*) &u
,
709 &addrlen
) == SOCKET_ERROR
)
712 if (u
.address
.sin_family
== AF_INET
)
714 laddr
= JvNewByteArray (4);
715 memcpy (elements (laddr
), &u
.address
.sin_addr
, 4);
718 else if (u
.address
.sin_family
== AF_INET6
)
720 laddr
= JvNewByteArray (16);
721 memcpy (elements (laddr
), &u
.address6
.sin6_addr
, 16);
725 throw new ::java::net::SocketException
726 (JvNewStringUTF ("invalid family"));
727 localAddress
= new ::java::net::InetAddress (laddr
, NULL
);
732 case _Jv_IP_MULTICAST_IF_
:
733 throw new ::java::net::SocketException
734 (JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
737 case _Jv_IP_MULTICAST_IF2_
:
738 throw new ::java::net::SocketException
739 (JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
742 case _Jv_IP_MULTICAST_LOOP_
:
743 throw new ::java::net::SocketException
744 (JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
748 if (::getsockopt (native_fd
, SOL_SOCKET
, IP_TOS
, (char *) &val
,
749 &val_len
) == SOCKET_ERROR
)
751 return new ::java::lang::Integer (val
);
754 case _Jv_SO_REUSEADDR_
:
755 throw new ::java::net::SocketException
756 (JvNewStringUTF ("SO_REUSEADDR: not valid for TCP"));
759 case _Jv_SO_TIMEOUT_
:
760 return new ::java::lang::Integer (timeout
);
764 WSASetLastError (WSAENOPROTOOPT
);
768 _Jv_ThrowSocketException ();
770 // we should never get here
774 gnu::java::net::PlainSocketImpl::shutdownInput (void)
776 if (::shutdown (native_fd
, 0))
777 _Jv_ThrowSocketException ();
781 gnu::java::net::PlainSocketImpl::shutdownOutput (void)
783 if (::shutdown (native_fd
, 1))
784 _Jv_ThrowSocketException ();