Merge from mainline
[official-gcc.git] / libjava / gnu / java / net / natPlainSocketImplPosix.cc
blobbe9437cd7dba5339ba2a344e5a3f6eea4928af71
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
7 details. */
9 #include <config.h>
10 #include <platform.h>
12 #ifdef HAVE_SYS_IOCTL_H
13 #define BSD_COMP /* Get FIONREAD on Solaris2. */
14 #include <sys/ioctl.h>
15 #endif
17 // Pick up FIONREAD on Solaris 2.5.
18 #ifdef HAVE_SYS_FILIO_H
19 #include <sys/filio.h>
20 #endif
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <errno.h>
25 #include <string.h>
27 #if HAVE_BSTRING_H
28 // Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
29 #include <bstring.h>
30 #endif
32 #include <gcj/cni.h>
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>
55 union SockAddr
57 struct sockaddr_in address;
58 #ifdef HAVE_INET6
59 struct sockaddr_in6 address6;
60 #endif
63 void
64 gnu::java::net::PlainSocketImpl::create (jboolean stream)
66 int sock = _Jv_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
68 if (sock < 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.
78 native_fd = sock;
81 void
82 gnu::java::net::PlainSocketImpl::bind (::java::net::InetAddress *host, jint lport)
84 union SockAddr u;
85 struct sockaddr *ptr = (struct sockaddr *) &u.address;
86 jbyteArray haddress = host->addr;
87 jbyte *bytes = elements (haddress);
88 int len = haddress->length;
89 int i = 1;
91 if (len == 4)
93 u.address.sin_family = AF_INET;
95 if (host != NULL)
96 memcpy (&u.address.sin_addr, bytes, len);
97 else
98 u.address.sin_addr.s_addr = htonl (INADDR_ANY);
100 len = sizeof (struct sockaddr_in);
101 u.address.sin_port = htons (lport);
103 #ifdef HAVE_INET6
104 else if (len == 16)
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);
111 #endif
112 else
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);
122 if (lport != 0)
123 localport = lport;
124 else if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
125 localport = ntohs (u.address.sin_port);
126 else
127 goto error;
129 return;
132 error:
133 char* strerr = strerror (errno);
134 throw new ::java::net::BindException (JvNewStringUTF (strerr));
137 void
138 gnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress *addr,
139 jint timeout)
141 ::java::net::InetSocketAddress *tmp = (::java::net::InetSocketAddress*) addr;
142 ::java::net::InetAddress *host = tmp->getAddress();
143 jint rport = tmp->getPort();
145 // Set the SocketImpl's address and port fields before we try to
146 // connect. Note that the fact that these are set doesn't imply
147 // that we're actually connected to anything. We need to record
148 // this data before we attempt the connect, since non-blocking
149 // SocketChannels will use this and almost certainly throw timeout
150 // exceptions.
151 address = host;
152 port = rport;
154 union SockAddr u;
155 socklen_t addrlen = sizeof(u);
156 jbyteArray haddress = host->addr;
157 jbyte *bytes = elements (haddress);
158 int len = haddress->length;
159 struct sockaddr *ptr = (struct sockaddr *) &u.address;
160 if (len == 4)
162 u.address.sin_family = AF_INET;
163 memcpy (&u.address.sin_addr, bytes, len);
164 len = sizeof (struct sockaddr_in);
165 u.address.sin_port = htons (rport);
167 #ifdef HAVE_INET6
168 else if (len == 16)
170 u.address6.sin6_family = AF_INET6;
171 memcpy (&u.address6.sin6_addr, bytes, len);
172 len = sizeof (struct sockaddr_in6);
173 u.address6.sin6_port = htons (rport);
175 #endif
176 else
177 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
179 if (timeout > 0)
181 int flags = ::fcntl (native_fd, F_GETFL);
182 ::fcntl (native_fd, F_SETFL, flags | O_NONBLOCK);
184 if ((_Jv_connect (native_fd, ptr, len) != 0) && (errno != EINPROGRESS))
185 goto error;
187 fd_set fset;
188 struct timeval tv;
189 FD_ZERO(&fset);
190 FD_SET(native_fd, &fset);
191 tv.tv_sec = timeout / 1000;
192 tv.tv_usec = (timeout % 1000) * 1000;
193 int retval;
195 if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0)
196 goto error;
197 else if (retval == 0)
198 throw new ::java::net::SocketTimeoutException
199 (JvNewStringUTF ("Connect timed out"));
200 // Set the socket back into a blocking state.
201 ::fcntl (native_fd, F_SETFL, flags);
203 else
205 if (_Jv_connect (native_fd, ptr, len) != 0)
206 goto error;
209 // A bind may not have been done on this socket; if so, set localport now.
210 if (localport == 0)
212 if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
213 localport = ntohs (u.address.sin_port);
214 else
215 goto error;
218 return;
220 error:
221 char* strerr = strerror (errno);
222 throw new ::java::net::ConnectException (JvNewStringUTF (strerr));
225 void
226 gnu::java::net::PlainSocketImpl::listen (jint backlog)
228 if (::listen (native_fd, backlog) != 0)
230 char* strerr = strerror (errno);
231 throw new ::java::io::IOException (JvNewStringUTF (strerr));
235 static void
236 throw_on_sock_closed (gnu::java::net::PlainSocketImpl *soc_impl)
238 // Avoid races from asynchronous close().
239 JvSynchronize sync (soc_impl);
240 if (soc_impl->native_fd == -1)
242 using namespace java::net;
243 // Socket was closed.
244 SocketException *se =
245 new SocketException (JvNewStringUTF ("Socket Closed"));
246 throw se;
250 void
251 gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *s)
253 union SockAddr u;
254 socklen_t addrlen = sizeof(u);
255 int new_socket = 0;
257 // Do timeouts via select since SO_RCVTIMEO is not always available.
258 if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
260 fd_set fset;
261 struct timeval tv;
262 FD_ZERO(&fset);
263 FD_SET(native_fd, &fset);
264 tv.tv_sec = timeout / 1000;
265 tv.tv_usec = (timeout % 1000) * 1000;
266 int retval;
267 if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0)
268 goto error;
269 else if (retval == 0)
270 throw new ::java::net::SocketTimeoutException (
271 JvNewStringUTF("Accept timed out"));
274 new_socket = _Jv_accept (native_fd, (sockaddr*) &u, &addrlen);
276 if (new_socket < 0)
277 goto error;
279 _Jv_platform_close_on_exec (new_socket);
281 jbyteArray raddr;
282 jint rport;
283 if (u.address.sin_family == AF_INET)
285 raddr = JvNewByteArray (4);
286 memcpy (elements (raddr), &u.address.sin_addr, 4);
287 rport = ntohs (u.address.sin_port);
289 #ifdef HAVE_INET6
290 else if (u.address.sin_family == AF_INET6)
292 raddr = JvNewByteArray (16);
293 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
294 rport = ntohs (u.address6.sin6_port);
296 #endif
297 else
298 throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
300 s->native_fd = new_socket;
301 s->localport = localport;
302 s->address = new ::java::net::InetAddress (raddr, NULL);
303 s->port = rport;
304 return;
306 error:
307 char* strerr = strerror (errno);
308 throw_on_sock_closed (this);
309 throw new ::java::io::IOException (JvNewStringUTF (strerr));
312 // Close(shutdown) the socket.
313 void
314 gnu::java::net::PlainSocketImpl::close()
316 // Avoid races from asynchronous finalization.
317 JvSynchronize sync (this);
319 // Should we use shutdown here? Yes.
320 // How would that effect so_linger? Uncertain.
321 ::shutdown (native_fd, 2);
322 // Ignore errors in shutdown as we are closing and all the same
323 // errors are handled in the close.
324 int res = _Jv_close (native_fd);
326 if (res == -1)
328 // These three errors are not errors according to tests performed
329 // on the reference implementation.
330 if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
331 throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
333 // Safe place to reset the file pointer.
334 native_fd = -1;
335 timeout = 0;
338 static void
339 write_helper (jint native_fd, jbyte *bytes, jint len);
341 // Write a byte to the socket.
342 void
343 gnu::java::net::PlainSocketImpl$SocketOutputStream::write(jint b)
345 jbyte data = (jbyte) b;
346 write_helper (this$0->native_fd, &data, 1);
349 // Write some bytes to the socket.
350 void
351 gnu::java::net::PlainSocketImpl$SocketOutputStream::write(jbyteArray b, jint offset, jint len)
353 if (! b)
354 throw new ::java::lang::NullPointerException;
355 if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
356 throw new ::java::lang::ArrayIndexOutOfBoundsException;
358 write_helper (this$0->native_fd, elements (b) + offset * sizeof (jbyte), len);
361 static void
362 write_helper(jint native_fd, jbyte *bytes, jint len)
364 int written = 0;
366 while (len > 0)
368 int r = _Jv_write (native_fd, bytes, len);
370 if (r == -1)
372 if (::java::lang::Thread::interrupted())
374 ::java::io::InterruptedIOException *iioe
375 = new ::java::io::InterruptedIOException
376 (JvNewStringLatin1 (strerror (errno)));
377 iioe->bytesTransferred = written;
378 throw iioe;
380 // Some errors should not cause exceptions.
381 if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
382 throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
383 break;
386 written += r;
387 len -= r;
388 bytes += r;
392 void
393 gnu::java::net::PlainSocketImpl::sendUrgentData (jint)
395 throw new ::java::net::SocketException (JvNewStringLatin1 (
396 "PlainSocketImpl: sending of urgent data not supported by this socket"));
399 static jint
400 read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
401 jbyte *bytes, jint count);
403 // Read a single byte from the socket.
404 jint
405 gnu::java::net::PlainSocketImpl$SocketInputStream::read(void)
407 jbyte data;
409 if (read_helper (this$0, &data, 1) == 1)
410 return data & 0xFF;
412 return -1;
415 // Read count bytes into the buffer, starting at offset.
416 jint
417 gnu::java::net::PlainSocketImpl$SocketInputStream::read(jbyteArray buffer,
418 jint offset,
419 jint count)
421 if (! buffer)
422 throw new ::java::lang::NullPointerException;
424 jsize bsize = JvGetArrayLength (buffer);
426 if (offset < 0 || count < 0 || offset + count > bsize)
427 throw new ::java::lang::ArrayIndexOutOfBoundsException;
429 return read_helper (this$0,
430 elements (buffer) + offset * sizeof (jbyte), count);
433 static jint
434 read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
435 jbyte *bytes, jint count)
437 // If zero bytes were requested, short circuit so that recv
438 // doesn't signal EOF.
439 if (count == 0)
440 return 0;
442 // Do timeouts via select.
443 if (soc_impl->timeout > 0
444 && soc_impl->native_fd >= 0
445 && soc_impl->native_fd < FD_SETSIZE)
447 // Create the file descriptor set.
448 fd_set read_fds;
449 FD_ZERO (&read_fds);
450 FD_SET (soc_impl->native_fd, &read_fds);
451 // Create the timeout struct based on our internal timeout value.
452 struct timeval timeout_value;
453 timeout_value.tv_sec = soc_impl->timeout / 1000;
454 timeout_value.tv_usec =(soc_impl->timeout % 1000) * 1000;
455 // Select on the fds.
456 int sel_retval =
457 _Jv_select (soc_impl->native_fd + 1,
458 &read_fds, NULL, NULL, &timeout_value);
459 // We're only interested in the 0 return.
460 // error returns still require us to try to read
461 // the socket to see what happened.
462 if (sel_retval == 0)
464 ::java::net::SocketTimeoutException *timeoutException =
465 new ::java::net::SocketTimeoutException
466 (JvNewStringUTF ("Read timed out"));
467 throw timeoutException;
471 // Read the socket.
472 int r = ::recv (soc_impl->native_fd, (char *) bytes, count, 0);
474 if (r == 0)
476 throw_on_sock_closed (soc_impl);
477 return -1;
480 if (::java::lang::Thread::interrupted())
482 ::java::io::InterruptedIOException *iioe =
483 new ::java::io::InterruptedIOException
484 (JvNewStringUTF ("Read interrupted"));
485 iioe->bytesTransferred = r == -1 ? 0 : r;
486 throw iioe;
488 else if (r == -1)
490 throw_on_sock_closed (soc_impl);
491 // Some errors cause us to return end of stream...
492 if (errno == ENOTCONN)
493 return -1;
495 // Other errors need to be signalled.
496 throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
499 return r;
502 // How many bytes are available?
503 jint
504 gnu::java::net::PlainSocketImpl::available(void)
506 #if defined(FIONREAD) || defined(HAVE_SELECT)
507 int num = 0;
508 int r = 0;
509 bool num_set = false;
511 #if defined(FIONREAD)
512 r = ::ioctl (native_fd, FIONREAD, &num);
514 if (r == -1 && errno == ENOTTY)
516 // If the ioctl doesn't work, we don't care.
517 r = 0;
518 num = 0;
520 else
521 num_set = true;
522 #elif defined(HAVE_SELECT)
523 if (native_fd < 0)
525 errno = EBADF;
526 r = -1;
528 #endif
530 if (r == -1)
532 posix_error:
533 throw new ::java::io::IOException(JvNewStringUTF(strerror(errno)));
536 // If we didn't get anything we can use select.
538 #if defined(HAVE_SELECT)
539 if (! num_set)
540 if (! num_set && native_fd >= 0 && native_fd < FD_SETSIZE)
542 fd_set rd;
543 FD_ZERO (&rd);
544 FD_SET (native_fd, &rd);
545 struct timeval tv;
546 tv.tv_sec = 0;
547 tv.tv_usec = 0;
548 r = _Jv_select (native_fd + 1, &rd, NULL, NULL, &tv);
549 if(r == -1)
550 goto posix_error;
551 num = r == 0 ? 0 : 1;
553 #endif /* HAVE_SELECT */
555 return (jint) num;
556 #else
557 throw new ::java::io::IOException (JvNewStringUTF ("unimplemented"));
558 #endif
561 void
562 gnu::java::net::PlainSocketImpl::setOption (jint optID, ::java::lang::Object *value)
564 int val;
565 socklen_t val_len = sizeof (val);
567 if (native_fd < 0)
568 throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
570 if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
572 ::java::lang::Boolean *boolobj =
573 static_cast< ::java::lang::Boolean *> (value);
574 if (boolobj->booleanValue())
575 val = 1;
576 else
578 if (optID == _Jv_SO_LINGER_)
579 val = -1;
580 else
581 val = 0;
584 else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
586 ::java::lang::Integer *intobj =
587 static_cast< ::java::lang::Integer *> (value);
588 val = (int) intobj->intValue();
590 else
592 throw new ::java::lang::IllegalArgumentException (
593 JvNewStringLatin1 ("`value' must be Boolean or Integer"));
596 switch (optID)
598 case _Jv_TCP_NODELAY_ :
599 #ifdef TCP_NODELAY
600 if (::setsockopt (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
601 val_len) != 0)
602 goto error;
603 #else
604 throw new ::java::lang::InternalError
605 (JvNewStringUTF ("TCP_NODELAY not supported"));
606 #endif /* TCP_NODELAY */
607 return;
609 case _Jv_SO_KEEPALIVE_ :
610 if (::setsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
611 val_len) != 0)
612 goto error;
613 return;
615 case _Jv_SO_BROADCAST_ :
616 throw new ::java::net::SocketException
617 (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
618 return;
620 case _Jv_SO_OOBINLINE_ :
621 if (::setsockopt (native_fd, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
622 val_len) != 0)
623 goto error;
624 return;
626 case _Jv_SO_LINGER_ :
627 #ifdef SO_LINGER
628 struct linger l_val;
629 l_val.l_onoff = (val != -1);
630 l_val.l_linger = val;
632 if (::setsockopt (native_fd, SOL_SOCKET, SO_LINGER, (char *) &l_val,
633 sizeof(l_val)) != 0)
634 goto error;
635 #else
636 throw new ::java::lang::InternalError (
637 JvNewStringUTF ("SO_LINGER not supported"));
638 #endif /* SO_LINGER */
639 return;
641 case _Jv_SO_SNDBUF_ :
642 case _Jv_SO_RCVBUF_ :
643 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
644 int opt;
645 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
646 if (::setsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
647 goto error;
648 #else
649 throw new ::java::lang::InternalError (
650 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
651 #endif
652 return;
654 case _Jv_SO_BINDADDR_ :
655 throw new ::java::net::SocketException (
656 JvNewStringUTF ("SO_BINDADDR: read only option"));
657 return;
659 case _Jv_IP_MULTICAST_IF_ :
660 throw new ::java::net::SocketException (
661 JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
662 return;
664 case _Jv_IP_MULTICAST_IF2_ :
665 throw new ::java::net::SocketException (
666 JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
667 return;
669 case _Jv_IP_MULTICAST_LOOP_ :
670 throw new ::java::net::SocketException (
671 JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
672 return;
674 case _Jv_IP_TOS_ :
675 if (::setsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
676 val_len) != 0)
677 goto error;
678 return;
680 case _Jv_SO_REUSEADDR_ :
681 #if defined(SO_REUSEADDR)
682 if (::setsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
683 val_len) != 0)
684 goto error;
685 return;
686 #else
687 throw new ::java::lang::InternalError (
688 JvNewStringUTF ("SO_REUSEADDR not supported"));
689 #endif
691 case _Jv_SO_TIMEOUT_ :
692 timeout = val;
693 return;
695 default :
696 errno = ENOPROTOOPT;
699 error:
700 char* strerr = strerror (errno);
701 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
704 ::java::lang::Object *
705 gnu::java::net::PlainSocketImpl::getOption (jint optID)
707 int val;
708 socklen_t val_len = sizeof(val);
709 union SockAddr u;
710 socklen_t addrlen = sizeof(u);
711 struct linger l_val;
712 socklen_t l_val_len = sizeof(l_val);
714 switch (optID)
716 #ifdef TCP_NODELAY
717 case _Jv_TCP_NODELAY_ :
718 if (::getsockopt (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
719 &val_len) != 0)
720 goto error;
721 else
722 return new ::java::lang::Boolean (val != 0);
723 #else
724 throw new ::java::lang::InternalError
725 (JvNewStringUTF ("TCP_NODELAY not supported"));
726 #endif
727 break;
729 case _Jv_SO_LINGER_ :
730 #ifdef SO_LINGER
731 if (::getsockopt (native_fd, SOL_SOCKET, SO_LINGER, (char *) &l_val,
732 &l_val_len) != 0)
733 goto error;
735 if (l_val.l_onoff)
736 return new ::java::lang::Integer (l_val.l_linger);
737 else
738 return new ::java::lang::Boolean ((jboolean)false);
739 #else
740 throw new ::java::lang::InternalError
741 (JvNewStringUTF ("SO_LINGER not supported"));
742 #endif
743 break;
745 case _Jv_SO_KEEPALIVE_ :
746 if (::getsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
747 &val_len) != 0)
748 goto error;
749 else
750 return new ::java::lang::Boolean (val != 0);
752 case _Jv_SO_BROADCAST_ :
753 if (::getsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
754 &val_len) != 0)
755 goto error;
756 return new ::java::lang::Boolean ((jboolean)val);
758 case _Jv_SO_OOBINLINE_ :
759 if (::getsockopt (native_fd, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
760 &val_len) != 0)
761 goto error;
762 return new ::java::lang::Boolean ((jboolean)val);
764 case _Jv_SO_RCVBUF_ :
765 case _Jv_SO_SNDBUF_ :
766 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
767 int opt;
768 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
769 if (::getsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
770 goto error;
771 else
772 return new ::java::lang::Integer (val);
773 #else
774 throw new ::java::lang::InternalError
775 (JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
776 #endif
777 break;
778 case _Jv_SO_BINDADDR_:
779 // cache the local address
780 if (localAddress == NULL)
782 jbyteArray laddr;
784 if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != 0)
785 goto error;
787 if (u.address.sin_family == AF_INET)
789 laddr = JvNewByteArray (4);
790 memcpy (elements (laddr), &u.address.sin_addr, 4);
792 #ifdef HAVE_INET6
793 else if (u.address.sin_family == AF_INET6)
795 laddr = JvNewByteArray (16);
796 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
798 #endif
799 else
800 throw new ::java::net::SocketException
801 (JvNewStringUTF ("invalid family"));
802 localAddress = new ::java::net::InetAddress (laddr, NULL);
805 return localAddress;
806 break;
807 case _Jv_IP_MULTICAST_IF_ :
808 throw new ::java::net::SocketException
809 (JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
810 break;
812 case _Jv_IP_MULTICAST_IF2_ :
813 throw new ::java::net::SocketException
814 (JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
815 break;
817 case _Jv_IP_MULTICAST_LOOP_ :
818 throw new ::java::net::SocketException
819 (JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
820 break;
822 case _Jv_IP_TOS_ :
823 if (::getsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
824 &val_len) != 0)
825 goto error;
826 return new ::java::lang::Integer (val);
827 break;
829 case _Jv_SO_REUSEADDR_ :
830 #if defined(SO_REUSEADDR)
831 if (::getsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
832 &val_len) != 0)
833 goto error;
834 #else
835 throw new ::java::lang::InternalError (
836 JvNewStringUTF ("SO_REUSEADDR not supported"));
837 #endif
838 break;
840 case _Jv_SO_TIMEOUT_ :
841 return new ::java::lang::Integer (timeout);
842 break;
844 default :
845 errno = ENOPROTOOPT;
848 error:
849 char* strerr = strerror (errno);
850 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
853 void
854 gnu::java::net::PlainSocketImpl::shutdownInput (void)
856 if (::shutdown (native_fd, 0))
857 throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));
860 void
861 gnu::java::net::PlainSocketImpl::shutdownOutput (void)
863 if (::shutdown (native_fd, 1))
864 throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));