Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / gnu / java / net / natPlainSocketImplPosix.cc
blob46b56bb6efbf3cfb8f4ba278a93529d2cb8e2aa2
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
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 union SockAddr u;
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;
151 if (len == 4)
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);
158 #ifdef HAVE_INET6
159 else if (len == 16)
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);
166 #endif
167 else
168 throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
170 if (timeout > 0)
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))
176 goto error;
178 fd_set fset;
179 struct timeval tv;
180 FD_ZERO(&fset);
181 FD_SET(native_fd, &fset);
182 tv.tv_sec = timeout / 1000;
183 tv.tv_usec = (timeout % 1000) * 1000;
184 int retval;
186 if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0)
187 goto error;
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);
194 else
196 if (_Jv_connect (native_fd, ptr, len) != 0)
197 goto error;
200 address = host;
201 port = rport;
203 // A bind may not have been done on this socket; if so, set localport now.
204 if (localport == 0)
206 if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
207 localport = ntohs (u.address.sin_port);
208 else
209 goto error;
212 return;
214 error:
215 char* strerr = strerror (errno);
216 throw new ::java::net::ConnectException (JvNewStringUTF (strerr));
219 void
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));
229 void
230 gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *s)
232 union SockAddr u;
233 socklen_t addrlen = sizeof(u);
234 int new_socket = 0;
236 // Do timeouts via select since SO_RCVTIMEO is not always available.
237 if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
239 fd_set fset;
240 struct timeval tv;
241 FD_ZERO(&fset);
242 FD_SET(native_fd, &fset);
243 tv.tv_sec = timeout / 1000;
244 tv.tv_usec = (timeout % 1000) * 1000;
245 int retval;
246 if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0)
247 goto error;
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);
255 if (new_socket < 0)
256 goto error;
258 _Jv_platform_close_on_exec (new_socket);
260 jbyteArray raddr;
261 jint rport;
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);
268 #ifdef HAVE_INET6
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);
275 #endif
276 else
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);
282 s->port = rport;
283 return;
285 error:
286 char* strerr = strerror (errno);
287 throw new ::java::io::IOException (JvNewStringUTF (strerr));
290 // Close(shutdown) the socket.
291 void
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);
300 if (res == -1)
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.
308 native_fd = -1;
309 timeout = 0;
312 static void
313 write_helper (jint native_fd, jbyte *bytes, jint len);
315 // Write a byte to the socket.
316 void
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.
324 void
325 gnu::java::net::PlainSocketImpl$SocketOutputStream::write(jbyteArray b, jint offset, jint len)
327 if (! b)
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);
335 static void
336 write_helper(jint native_fd, jbyte *bytes, jint len)
338 int written = 0;
340 while (len > 0)
342 int r = _Jv_write (native_fd, bytes, len);
344 if (r == -1)
346 if (::java::lang::Thread::interrupted())
348 ::java::io::InterruptedIOException *iioe
349 = new ::java::io::InterruptedIOException
350 (JvNewStringLatin1 (strerror (errno)));
351 iioe->bytesTransferred = written;
352 throw iioe;
354 // Some errors should not cause exceptions.
355 if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
356 throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
357 break;
360 written += r;
361 len -= r;
362 bytes += r;
366 void
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"));
373 static jint
374 read_helper (jint native_fd, jint timeout, jbyte *bytes, jint count);
376 // Read a single byte from the socket.
377 jint
378 gnu::java::net::PlainSocketImpl$SocketInputStream::read(void)
380 jbyte data;
382 if (read_helper (this$0->native_fd, this$0->timeout, &data, 1) == 1)
383 return data & 0xFF;
385 return -1;
388 // Read count bytes into the buffer, starting at offset.
389 jint
390 gnu::java::net::PlainSocketImpl$SocketInputStream::read(jbyteArray buffer, jint offset,
391 jint count)
393 if (! buffer)
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);
405 static jint
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.
412 fd_set read_fds;
413 FD_ZERO (&read_fds);
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.
420 int sel_retval =
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.
425 if (sel_retval == 0)
427 ::java::net::SocketTimeoutException *timeoutException =
428 new ::java::net::SocketTimeoutException
429 (JvNewStringUTF ("Read timed out"));
430 throw timeoutException;
434 // Read the socket.
435 int r = ::recv (native_fd, (char *) bytes, count, 0);
437 if (r == 0)
438 return -1;
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;
446 throw iioe;
448 else if (r == -1)
450 // Some errors cause us to return end of stream...
451 if (errno == ENOTCONN)
452 return -1;
454 // Other errors need to be signalled.
455 throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
458 return r;
461 // How many bytes are available?
462 jint
463 gnu::java::net::PlainSocketImpl::available(void)
465 #if defined(FIONREAD) || defined(HAVE_SELECT)
466 int num = 0;
467 int r = 0;
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.
476 r = 0;
477 num = 0;
479 else
480 num_set = true;
481 #elif defined(HAVE_SELECT)
482 if (native_fd < 0)
484 errno = EBADF;
485 r = -1;
487 #endif
489 if (r == -1)
491 posix_error:
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)
498 if (! num_set)
499 if (! num_set && native_fd >= 0 && native_fd < FD_SETSIZE)
501 fd_set rd;
502 FD_ZERO (&rd);
503 FD_SET (native_fd, &rd);
504 struct timeval tv;
505 tv.tv_sec = 0;
506 tv.tv_usec = 0;
507 r = _Jv_select (native_fd + 1, &rd, NULL, NULL, &tv);
508 if(r == -1)
509 goto posix_error;
510 num = r == 0 ? 0 : 1;
512 #endif /* HAVE_SELECT */
514 return (jint) num;
515 #else
516 throw new ::java::io::IOException (JvNewStringUTF ("unimplemented"));
517 #endif
520 void
521 gnu::java::net::PlainSocketImpl::setOption (jint optID, ::java::lang::Object *value)
523 int val;
524 socklen_t val_len = sizeof (val);
526 if (native_fd < 0)
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())
534 val = 1;
535 else
537 if (optID == _Jv_SO_LINGER_)
538 val = -1;
539 else
540 val = 0;
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();
549 else
551 throw new ::java::lang::IllegalArgumentException (
552 JvNewStringLatin1 ("`value' must be Boolean or Integer"));
555 switch (optID)
557 case _Jv_TCP_NODELAY_ :
558 #ifdef TCP_NODELAY
559 if (::setsockopt (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
560 val_len) != 0)
561 goto error;
562 #else
563 throw new ::java::lang::InternalError
564 (JvNewStringUTF ("TCP_NODELAY not supported"));
565 #endif /* TCP_NODELAY */
566 return;
568 case _Jv_SO_KEEPALIVE_ :
569 if (::setsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
570 val_len) != 0)
571 goto error;
572 return;
574 case _Jv_SO_BROADCAST_ :
575 throw new ::java::net::SocketException
576 (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
577 return;
579 case _Jv_SO_OOBINLINE_ :
580 if (::setsockopt (native_fd, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
581 val_len) != 0)
582 goto error;
583 return;
585 case _Jv_SO_LINGER_ :
586 #ifdef SO_LINGER
587 struct linger l_val;
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,
592 sizeof(l_val)) != 0)
593 goto error;
594 #else
595 throw new ::java::lang::InternalError (
596 JvNewStringUTF ("SO_LINGER not supported"));
597 #endif /* SO_LINGER */
598 return;
600 case _Jv_SO_SNDBUF_ :
601 case _Jv_SO_RCVBUF_ :
602 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
603 int opt;
604 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
605 if (::setsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
606 goto error;
607 #else
608 throw new ::java::lang::InternalError (
609 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
610 #endif
611 return;
613 case _Jv_SO_BINDADDR_ :
614 throw new ::java::net::SocketException (
615 JvNewStringUTF ("SO_BINDADDR: read only option"));
616 return;
618 case _Jv_IP_MULTICAST_IF_ :
619 throw new ::java::net::SocketException (
620 JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
621 return;
623 case _Jv_IP_MULTICAST_IF2_ :
624 throw new ::java::net::SocketException (
625 JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
626 return;
628 case _Jv_IP_MULTICAST_LOOP_ :
629 throw new ::java::net::SocketException (
630 JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
631 return;
633 case _Jv_IP_TOS_ :
634 if (::setsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
635 val_len) != 0)
636 goto error;
637 return;
639 case _Jv_SO_REUSEADDR_ :
640 #if defined(SO_REUSEADDR)
641 if (::setsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
642 val_len) != 0)
643 goto error;
644 #else
645 throw new ::java::lang::InternalError (
646 JvNewStringUTF ("SO_REUSEADDR not supported"));
647 #endif
649 case _Jv_SO_TIMEOUT_ :
650 timeout = val;
651 return;
653 default :
654 errno = ENOPROTOOPT;
657 error:
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)
665 int val;
666 socklen_t val_len = sizeof(val);
667 union SockAddr u;
668 socklen_t addrlen = sizeof(u);
669 struct linger l_val;
670 socklen_t l_val_len = sizeof(l_val);
672 switch (optID)
674 #ifdef TCP_NODELAY
675 case _Jv_TCP_NODELAY_ :
676 if (::getsockopt (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
677 &val_len) != 0)
678 goto error;
679 else
680 return new ::java::lang::Boolean (val != 0);
681 #else
682 throw new ::java::lang::InternalError
683 (JvNewStringUTF ("TCP_NODELAY not supported"));
684 #endif
685 break;
687 case _Jv_SO_LINGER_ :
688 #ifdef SO_LINGER
689 if (::getsockopt (native_fd, SOL_SOCKET, SO_LINGER, (char *) &l_val,
690 &l_val_len) != 0)
691 goto error;
693 if (l_val.l_onoff)
694 return new ::java::lang::Integer (l_val.l_linger);
695 else
696 return new ::java::lang::Boolean ((jboolean)false);
697 #else
698 throw new ::java::lang::InternalError
699 (JvNewStringUTF ("SO_LINGER not supported"));
700 #endif
701 break;
703 case _Jv_SO_KEEPALIVE_ :
704 if (::getsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
705 &val_len) != 0)
706 goto error;
707 else
708 return new ::java::lang::Boolean (val != 0);
710 case _Jv_SO_BROADCAST_ :
711 if (::getsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
712 &val_len) != 0)
713 goto error;
714 return new ::java::lang::Boolean ((jboolean)val);
716 case _Jv_SO_OOBINLINE_ :
717 if (::getsockopt (native_fd, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
718 &val_len) != 0)
719 goto error;
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)
725 int opt;
726 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
727 if (::getsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
728 goto error;
729 else
730 return new ::java::lang::Integer (val);
731 #else
732 throw new ::java::lang::InternalError
733 (JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
734 #endif
735 break;
736 case _Jv_SO_BINDADDR_:
737 // cache the local address
738 if (localAddress == NULL)
740 jbyteArray laddr;
742 if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != 0)
743 goto error;
745 if (u.address.sin_family == AF_INET)
747 laddr = JvNewByteArray (4);
748 memcpy (elements (laddr), &u.address.sin_addr, 4);
750 #ifdef HAVE_INET6
751 else if (u.address.sin_family == AF_INET6)
753 laddr = JvNewByteArray (16);
754 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
756 #endif
757 else
758 throw new ::java::net::SocketException
759 (JvNewStringUTF ("invalid family"));
760 localAddress = new ::java::net::InetAddress (laddr, NULL);
763 return localAddress;
764 break;
765 case _Jv_IP_MULTICAST_IF_ :
766 throw new ::java::net::SocketException
767 (JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
768 break;
770 case _Jv_IP_MULTICAST_IF2_ :
771 throw new ::java::net::SocketException
772 (JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
773 break;
775 case _Jv_IP_MULTICAST_LOOP_ :
776 throw new ::java::net::SocketException
777 (JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
778 break;
780 case _Jv_IP_TOS_ :
781 if (::getsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
782 &val_len) != 0)
783 goto error;
784 return new ::java::lang::Integer (val);
785 break;
787 case _Jv_SO_REUSEADDR_ :
788 #if defined(SO_REUSEADDR)
789 if (::getsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
790 &val_len) != 0)
791 goto error;
792 #else
793 throw new ::java::lang::InternalError (
794 JvNewStringUTF ("SO_REUSEADDR not supported"));
795 #endif
796 break;
798 case _Jv_SO_TIMEOUT_ :
799 return new ::java::lang::Integer (timeout);
800 break;
802 default :
803 errno = ENOPROTOOPT;
806 error:
807 char* strerr = strerror (errno);
808 throw new ::java::net::SocketException (JvNewStringUTF (strerr));
811 void
812 gnu::java::net::PlainSocketImpl::shutdownInput (void)
814 if (::shutdown (native_fd, 0))
815 throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));
818 void
819 gnu::java::net::PlainSocketImpl::shutdownOutput (void)
821 if (::shutdown (native_fd, 1))
822 throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));