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
14 // Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
18 #include <gnu/java/net/PlainDatagramSocketImpl.h>
19 #include <java/io/IOException.h>
20 #include <java/net/BindException.h>
21 #include <java/net/SocketException.h>
22 #include <java/net/InetAddress.h>
23 #include <java/net/NetworkInterface.h>
24 #include <java/net/DatagramPacket.h>
25 #include <java/net/PortUnreachableException.h>
26 #include <java/net/SocketTimeoutException.h>
27 #include <java/lang/InternalError.h>
28 #include <java/lang/Object.h>
29 #include <java/lang/Boolean.h>
30 #include <java/lang/Integer.h>
34 struct sockaddr_in address
;
36 struct sockaddr_in6 address6
;
42 #if HAVE_STRUCT_IP_MREQ
45 #if HAVE_STRUCT_IPV6_MREQ
46 struct ipv6_mreq mreq6
;
54 struct in6_addr addr6
;
58 // FIXME: routines here and/or in natPlainSocketImpl.cc could throw
59 // NoRouteToHostException; also consider UnknownHostException, ConnectException.
62 gnu::java::net::PlainDatagramSocketImpl::create ()
64 SOCKET sock
= ::socket (AF_INET
, SOCK_DGRAM
, 0);
66 if (sock
== INVALID_SOCKET
)
68 _Jv_ThrowSocketException ();
71 // Cast this to a HANDLE so we can make
72 // it non-inheritable via _Jv_platform_close_on_exec.
73 HANDLE hSocket
= (HANDLE
) sock
;
74 _Jv_platform_close_on_exec (hSocket
);
76 // We use native_fd in place of fd here. From leaving fd null we avoid
77 // the double close problem in FileDescriptor.finalize.
78 native_fd
= (jint
) hSocket
;
82 gnu::java::net::PlainDatagramSocketImpl::bind (jint lport
,
83 ::java::net::InetAddress
*host
)
86 struct sockaddr
*ptr
= (struct sockaddr
*) &u
.address
;
87 // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4.
88 jbyteArray haddress
= host
->addr
;
89 jbyte
*bytes
= elements (haddress
);
90 int len
= haddress
->length
;
94 u
.address
.sin_family
= AF_INET
;
97 memcpy (&u
.address
.sin_addr
, bytes
, len
);
99 u
.address
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
101 len
= sizeof (struct sockaddr_in
);
102 u
.address
.sin_port
= htons (lport
);
107 u
.address6
.sin6_family
= AF_INET6
;
108 memcpy (&u
.address6
.sin6_addr
, bytes
, len
);
109 len
= sizeof (struct sockaddr_in6
);
110 u
.address6
.sin6_port
= htons (lport
);
114 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
116 if (::bind (native_fd
, ptr
, len
) == 0)
118 socklen_t addrlen
= sizeof(u
);
122 else if (::getsockname (native_fd
, (sockaddr
*) &u
, &addrlen
) == 0)
123 localPort
= ntohs (u
.address
.sin_port
);
127 /* Allow broadcast by default. */
129 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_BROADCAST
, (char *) &broadcast
,
130 sizeof (broadcast
)) != 0)
137 DWORD dwErrorCode
= WSAGetLastError ();
138 throw new ::java::net::BindException (_Jv_WinStrError (dwErrorCode
));
142 gnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress
*, jint
)
144 throw new ::java::lang::InternalError (JvNewStringLatin1 (
145 "PlainDatagramSocketImpl::connect: not implemented yet"));
149 gnu::java::net::PlainDatagramSocketImpl::disconnect ()
151 throw new ::java::lang::InternalError (JvNewStringLatin1 (
152 "PlainDatagramSocketImpl::disconnect: not implemented yet"));
156 gnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress
*i
)
158 // FIXME: Deal with Multicast and if the socket is connected.
160 socklen_t addrlen
= sizeof(u
);
162 ::recvfrom (native_fd
, (char *) NULL
, 0, MSG_PEEK
, (sockaddr
*) &u
,
166 // FIXME: Deal with Multicast addressing and if the socket is connected.
169 if (u
.address
.sin_family
== AF_INET
)
171 raddr
= JvNewByteArray (4);
172 memcpy (elements (raddr
), &u
.address
.sin_addr
, 4);
173 rport
= ntohs (u
.address
.sin_port
);
176 else if (u
.address
.sin_family
== AF_INET6
)
178 raddr
= JvNewByteArray (16);
179 memcpy (elements (raddr
), &u
.address6
.sin6_addr
, 16);
180 rport
= ntohs (u
.address6
.sin6_port
);
184 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
189 DWORD dwErrorCode
= WSAGetLastError ();
190 if (dwErrorCode
== WSAECONNRESET
)
191 throw new ::java::net::PortUnreachableException (_Jv_WinStrError (dwErrorCode
));
193 _Jv_ThrowIOException ();
195 // we should never get here
199 gnu::java::net::PlainDatagramSocketImpl::peekData(::java::net::DatagramPacket
*p
)
201 // FIXME: Deal with Multicast and if the socket is connected.
203 socklen_t addrlen
= sizeof(u
);
204 jbyte
*dbytes
= elements (p
->getData()) + p
->getOffset();
205 jint maxlen
= p
->maxlen
- p
->getOffset();
210 int nRet
= ::setsockopt(native_fd
, SOL_SOCKET
, SO_RCVTIMEO
,
211 (char*)&timeout
, sizeof(timeout
));
212 if (nRet
!= NO_ERROR
)
217 ::recvfrom (native_fd
, (char *) dbytes
, maxlen
, MSG_PEEK
, (sockaddr
*) &u
,
219 if (retlen
== SOCKET_ERROR
)
221 // FIXME: Deal with Multicast addressing and if the socket is connected.
224 if (u
.address
.sin_family
== AF_INET
)
226 raddr
= JvNewByteArray (4);
227 memcpy (elements (raddr
), &u
.address
.sin_addr
, 4);
228 rport
= ntohs (u
.address
.sin_port
);
231 else if (u
.address
.sin_family
== AF_INET6
)
233 raddr
= JvNewByteArray (16);
234 memcpy (elements (raddr
), &u
.address6
.sin6_addr
, 16);
235 rport
= ntohs (u
.address6
.sin6_port
);
239 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
241 p
->setAddress (new ::java::net::InetAddress (raddr
, NULL
));
243 p
->length
= (jint
) retlen
;
247 DWORD dwErrorCode
= WSAGetLastError ();
248 if (dwErrorCode
== WSAECONNRESET
)
249 throw new ::java::net::PortUnreachableException (_Jv_WinStrError (dwErrorCode
));
250 else if (dwErrorCode
== WSAETIMEDOUT
)
251 throw new ::java::net::SocketTimeoutException (_Jv_WinStrError (dwErrorCode
));
253 _Jv_ThrowIOException ();
256 // we should never get here
259 // Close(shutdown) the socket.
261 gnu::java::net::PlainDatagramSocketImpl::close ()
263 // Avoid races from asynchronous finalization.
264 JvSynchronize
sync (this);
266 // The method isn't declared to throw anything, so we disregard
268 ::closesocket (native_fd
);
274 gnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket
*p
)
276 JvSynchronize
lock (SEND_LOCK
);
278 // FIXME: Deal with Multicast and if the socket is connected.
279 jint rport
= p
->getPort();
281 jbyteArray haddress
= p
->getAddress()->addr
;
282 jbyte
*bytes
= elements (haddress
);
283 int len
= haddress
->length
;
284 struct sockaddr
*ptr
= (struct sockaddr
*) &u
.address
;
285 jbyte
*dbytes
= elements (p
->getData()) + p
->getOffset();
288 u
.address
.sin_family
= AF_INET
;
289 memcpy (&u
.address
.sin_addr
, bytes
, len
);
290 len
= sizeof (struct sockaddr_in
);
291 u
.address
.sin_port
= htons (rport
);
296 u
.address6
.sin6_family
= AF_INET6
;
297 memcpy (&u
.address6
.sin6_addr
, bytes
, len
);
298 len
= sizeof (struct sockaddr_in6
);
299 u
.address6
.sin6_port
= htons (rport
);
303 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
305 if (::sendto (native_fd
, (char *) dbytes
, p
->getLength(), 0, ptr
, len
) >= 0)
308 DWORD dwErrorCode
= WSAGetLastError ();
309 if (dwErrorCode
== WSAECONNRESET
)
310 throw new ::java::net::PortUnreachableException (_Jv_WinStrError (dwErrorCode
));
312 _Jv_ThrowIOException ();
316 gnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket
*p
)
318 JvSynchronize
lock (RECEIVE_LOCK
);
320 // FIXME: Deal with Multicast and if the socket is connected.
322 socklen_t addrlen
= sizeof(u
);
323 jbyte
*dbytes
= elements (p
->getData()) + p
->getOffset();
324 jint maxlen
= p
->maxlen
- p
->getOffset();
329 // This implementation doesn't allow specifying an infinite
330 // timeout after specifying a finite one, but Sun's JDK 1.4.1
331 // didn't seem to allow this either....
332 int nRet
= ::setsockopt(native_fd
, SOL_SOCKET
, SO_RCVTIMEO
,
333 (char*)&timeout
, sizeof(timeout
));
334 if (nRet
!= NO_ERROR
)
339 ::recvfrom (native_fd
, (char *) dbytes
, maxlen
, 0, (sockaddr
*) &u
,
343 // FIXME: Deal with Multicast addressing and if the socket is connected.
346 if (u
.address
.sin_family
== AF_INET
)
348 raddr
= JvNewByteArray (4);
349 memcpy (elements (raddr
), &u
.address
.sin_addr
, 4);
350 rport
= ntohs (u
.address
.sin_port
);
353 else if (u
.address
.sin_family
== AF_INET6
)
355 raddr
= JvNewByteArray (16);
356 memcpy (elements (raddr
), &u
.address6
.sin6_addr
, 16);
357 rport
= ntohs (u
.address6
.sin6_port
);
361 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
363 p
->setAddress (new ::java::net::InetAddress (raddr
, NULL
));
365 p
->length
= (jint
) retlen
;
369 DWORD dwErrorCode
= WSAGetLastError();
370 if (dwErrorCode
== WSAECONNRESET
)
371 throw new ::java::net::PortUnreachableException (_Jv_WinStrError (dwErrorCode
));
372 else if (dwErrorCode
== WSAETIMEDOUT
)
373 throw new ::java::net::SocketTimeoutException (_Jv_WinStrError (dwErrorCode
));
375 throw new ::java::io::IOException (_Jv_WinStrError (dwErrorCode
));
379 gnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl
)
381 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
382 char val
= (char) ttl
;
383 socklen_t val_len
= sizeof(val
);
385 if (::setsockopt (native_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &val
, val_len
) == 0)
388 _Jv_ThrowIOException ();
392 gnu::java::net::PlainDatagramSocketImpl::getTimeToLive ()
394 // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
396 socklen_t val_len
= sizeof(val
);
398 if (::getsockopt (native_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &val
, &val_len
) == 0)
399 return ((int) val
) & 0xFF;
401 _Jv_ThrowIOException ();
404 // we should never get here
408 gnu::java::net::PlainDatagramSocketImpl::mcastGrp (::java::net::InetAddress
*inetaddr
,
409 ::java::net::NetworkInterface
*,
412 // FIXME: implement use of NetworkInterface
413 jbyteArray haddress
= inetaddr
->addr
;
414 int len
= haddress
->length
;
419 #if HAVE_STRUCT_IP_MREQ
423 opname
= join
? IP_ADD_MEMBERSHIP
: IP_DROP_MEMBERSHIP
;
424 memcpy (&u
.mreq
.imr_multiaddr
, bytes
, len
);
425 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
426 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
427 u
.mreq
.imr_interface
.s_addr
= htonl (INADDR_ANY
);
428 len
= sizeof (struct ip_mreq
);
429 ptr
= (const char *) &u
.mreq
;
432 #if HAVE_STRUCT_IPV6_MREQ
435 level
= IPPROTO_IPV6
;
437 /* Prefer new RFC 2553 names. */
438 #ifndef IPV6_JOIN_GROUP
439 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
441 #ifndef IPV6_LEAVE_GROUP
442 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
445 opname
= join
? IPV6_JOIN_GROUP
: IPV6_LEAVE_GROUP
;
446 memcpy (&u
.mreq6
.ipv6mr_multiaddr
, bytes
, len
);
447 // FIXME: If a non-default interface is set, use it; see Stevens p. 501.
448 // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
449 u
.mreq6
.ipv6mr_interface
= 0;
450 len
= sizeof (struct ipv6_mreq
);
451 ptr
= (const char *) &u
.mreq6
;
455 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
457 if (::setsockopt (native_fd
, level
, opname
, ptr
, len
) == 0)
460 _Jv_ThrowIOException ();
464 gnu::java::net::PlainDatagramSocketImpl::setOption (jint optID
,
465 ::java::lang::Object
*value
)
468 socklen_t val_len
= sizeof (val
);
471 throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
473 if (_Jv_IsInstanceOf (value
, &::java::lang::Boolean::class$
))
475 ::java::lang::Boolean
*boolobj
=
476 static_cast< ::java::lang::Boolean
*> (value
);
477 val
= boolobj
->booleanValue() ? 1 : 0;
479 else if (_Jv_IsInstanceOf (value
, &::java::lang::Integer::class$
))
481 ::java::lang::Integer
*intobj
=
482 static_cast< ::java::lang::Integer
*> (value
);
483 val
= (int) intobj
->intValue();
485 // Else assume value to be an InetAddress for use with IP_MULTICAST_IF.
489 case _Jv_TCP_NODELAY_
:
490 throw new ::java::net::SocketException (
491 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
493 case _Jv_SO_LINGER_
:
494 throw new ::java::net::SocketException (
495 JvNewStringUTF ("SO_LINGER not valid for UDP"));
497 case _Jv_SO_KEEPALIVE_
:
498 throw new ::java::net::SocketException (
499 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
502 case _Jv_SO_BROADCAST_
:
503 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_BROADCAST
, (char *) &val
,
508 case _Jv_SO_OOBINLINE_
:
509 throw new ::java::net::SocketException (
510 JvNewStringUTF ("SO_OOBINLINE: not valid for UDP"));
513 case _Jv_SO_SNDBUF_
:
514 case _Jv_SO_RCVBUF_
:
516 optID
== _Jv_SO_SNDBUF_
? opt
= SO_SNDBUF
: opt
= SO_RCVBUF
;
517 if (::setsockopt (native_fd
, SOL_SOCKET
, opt
, (char *) &val
, val_len
) != 0)
520 case _Jv_SO_REUSEADDR_
:
521 if (::setsockopt (native_fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &val
,
525 case _Jv_SO_BINDADDR_
:
526 throw new ::java::net::SocketException (
527 JvNewStringUTF ("SO_BINDADDR: read only option"));
529 case _Jv_IP_MULTICAST_IF_
:
537 haddress
= ((::java::net::InetAddress
*) value
)->addr
;
538 bytes
= elements (haddress
);
539 len
= haddress
->length
;
543 opname
= IP_MULTICAST_IF
;
544 memcpy (&u
.addr
, bytes
, len
);
545 len
= sizeof (struct in_addr
);
546 ptr
= (const char *) &u
.addr
;
548 // Tru64 UNIX V5.0 has struct sockaddr_in6, but no IPV6_MULTICAST_IF
549 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_IF)
552 level
= IPPROTO_IPV6
;
553 opname
= IPV6_MULTICAST_IF
;
554 memcpy (&u
.addr6
, bytes
, len
);
555 len
= sizeof (struct in6_addr
);
556 ptr
= (const char *) &u
.addr6
;
561 new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
563 if (::setsockopt (native_fd
, level
, opname
, ptr
, len
) != 0)
567 case _Jv_IP_MULTICAST_IF2_
:
568 throw new ::java::net::SocketException (
569 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
572 case _Jv_IP_MULTICAST_LOOP_
:
573 throw new ::java::net::SocketException (
574 JvNewStringUTF ("IP_MULTICAST_LOOP: not yet implemented"));
578 if (::setsockopt (native_fd
, SOL_SOCKET
, IP_TOS
, (char *) &val
,
583 case _Jv_SO_TIMEOUT_
:
587 WSASetLastError (WSAENOPROTOOPT
);
591 _Jv_ThrowSocketException ();
594 ::java::lang::Object
*
595 gnu::java::net::PlainDatagramSocketImpl::getOption (jint optID
)
598 socklen_t val_len
= sizeof(val
);
600 socklen_t addrlen
= sizeof(u
);
604 case _Jv_TCP_NODELAY_
:
605 throw new ::java::net::SocketException (
606 JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
608 case _Jv_SO_LINGER_
:
609 throw new ::java::net::SocketException (
610 JvNewStringUTF ("SO_LINGER not valid for UDP"));
612 case _Jv_SO_KEEPALIVE_
:
613 throw new ::java::net::SocketException (
614 JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
617 case _Jv_SO_BROADCAST_
:
618 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_BROADCAST
, (char *) &val
,
621 return new ::java::lang::Boolean (val
!= 0);
623 case _Jv_SO_OOBINLINE_
:
624 throw new ::java::net::SocketException (
625 JvNewStringUTF ("SO_OOBINLINE not valid for UDP"));
628 case _Jv_SO_RCVBUF_
:
629 case _Jv_SO_SNDBUF_
:
631 optID
== _Jv_SO_SNDBUF_
? opt
= SO_SNDBUF
: opt
= SO_RCVBUF
;
632 if (::getsockopt (native_fd
, SOL_SOCKET
, opt
, (char *) &val
, &val_len
) != 0)
635 return new ::java::lang::Integer (val
);
637 case _Jv_SO_BINDADDR_
:
638 // cache the local address
639 if (localAddress
== NULL
)
642 if (::getsockname (native_fd
, (sockaddr
*) &u
, &addrlen
) != 0)
644 if (u
.address
.sin_family
== AF_INET
)
646 laddr
= JvNewByteArray (4);
647 memcpy (elements (laddr
), &u
.address
.sin_addr
, 4);
650 else if (u
.address
.sin_family
== AF_INET6
)
652 laddr
= JvNewByteArray (16);
653 memcpy (elements (laddr
), &u
.address6
.sin6_addr
, 16);
657 throw new ::java::net::SocketException (
658 JvNewStringUTF ("invalid family"));
659 localAddress
= new ::java::net::InetAddress (laddr
, NULL
);
663 case _Jv_SO_REUSEADDR_
:
664 if (::getsockopt (native_fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &val
,
667 return new ::java::lang::Boolean (val
!= 0);
669 case _Jv_IP_MULTICAST_IF_
:
670 struct in_addr inaddr
;
671 socklen_t inaddr_len
;
674 inaddr_len
= sizeof(inaddr
);
675 if (::getsockopt (native_fd
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &inaddr
,
679 bytes
= inet_ntoa (inaddr
);
681 return ::java::net::InetAddress::getByName (JvNewStringLatin1 (bytes
));
683 case _Jv_SO_TIMEOUT_
:
684 return new ::java::lang::Integer (timeout
);
687 case _Jv_IP_MULTICAST_IF2_
:
688 throw new ::java::net::SocketException (
689 JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
692 case _Jv_IP_MULTICAST_LOOP_
:
693 if (::getsockopt (native_fd
, SOL_SOCKET
, IP_MULTICAST_LOOP
, (char *) &val
,
696 return new ::java::lang::Boolean (val
!= 0);
699 if (::getsockopt (native_fd
, SOL_SOCKET
, IP_TOS
, (char *) &val
,
702 return new ::java::lang::Integer (val
);
705 WSASetLastError (WSAENOPROTOOPT
);
709 _Jv_ThrowSocketException ();
711 // we should never get here