OSDN Git Service

https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=233406
[pf3gnuchains/gcc-fork.git] / libjava / gnu / java / net / natPlainSocketImplPosix.cc
1 /* Copyright (C) 2003, 2004, 2005, 2006, 2007  Free Software Foundation
2
3    This file is part of libgcj.
4
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
7 details.  */
8
9 #include <config.h>
10 #include <platform.h>
11
12 #ifdef HAVE_SYS_IOCTL_H
13 #define BSD_COMP /* Get FIONREAD on Solaris2. */
14 #include <sys/ioctl.h>
15 #endif
16
17 // Pick up FIONREAD on Solaris 2.5.
18 #ifdef HAVE_SYS_FILIO_H
19 #include <sys/filio.h>
20 #endif
21
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <errno.h>
25 #include <string.h>
26
27 #if HAVE_BSTRING_H
28 // Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2 
29 #include <bstring.h>
30 #endif
31
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>
54 #include <java/net/UnknownHostException.h>
55
56 union SockAddr
57 {
58   struct sockaddr_in address;
59 #ifdef HAVE_INET6
60   struct sockaddr_in6 address6;
61 #endif
62 };
63
64 void
65 gnu::java::net::PlainSocketImpl::create (jboolean stream)
66 {
67   // We might already have been create()d in the nio case.
68   if (native_fd != -1)
69     return;
70
71   int sock = _Jv_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
72
73   if (sock < 0)
74     {
75       char* strerr = strerror (errno);
76       throw new ::java::io::IOException (JvNewStringUTF (strerr));
77     }
78
79   // We use native_fd in place of fd here.  From leaving fd null we avoid
80   // the double close problem in FileDescriptor.finalize.
81   native_fd = sock;
82 }
83
84 void
85 gnu::java::net::PlainSocketImpl::bind (::java::net::InetAddress *host, jint lport)
86 {
87   union SockAddr u;
88   struct sockaddr *ptr = (struct sockaddr *) &u.address;
89   jbyteArray haddress = host->addr;
90   jbyte *bytes = elements (haddress);
91   int len = haddress->length;
92   int i = 1;
93
94   // The following is needed for OS X/PPC, otherwise bind() fails with an
95   // error. I found the issue and following fix on some mailing list, but
96   // no explanation was given as to why this solved the problem.
97   memset (&u, 0, sizeof (u));
98
99   if (len == 4)
100     {
101       u.address.sin_family = AF_INET;
102
103       if (host != NULL)
104         memcpy (&u.address.sin_addr, bytes, len);
105       else
106         u.address.sin_addr.s_addr = htonl (INADDR_ANY);
107
108       len = sizeof (struct sockaddr_in);
109       u.address.sin_port = htons (lport);
110     }
111 #ifdef HAVE_INET6
112   else if (len == 16)
113     {
114       u.address6.sin6_family = AF_INET6;
115       memcpy (&u.address6.sin6_addr, bytes, len);
116       len = sizeof (struct sockaddr_in6);
117       u.address6.sin6_port = htons (lport);
118     }
119 #endif
120   else
121     throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
122
123   // Enable SO_REUSEADDR, so that servers can reuse ports left in TIME_WAIT.
124   ::setsockopt(native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof(i));
125   
126   if (_Jv_bind (native_fd, ptr, len) == 0)
127     {
128       socklen_t addrlen = sizeof(u);
129
130       if (lport != 0)
131         localport = lport;
132       else if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
133         localport = ntohs (u.address.sin_port);
134       else
135         goto error;
136
137       return;
138     }
139
140  error:
141   char* strerr = strerror (errno);
142   throw new ::java::net::BindException (JvNewStringUTF (strerr));
143 }
144
145 void
146 gnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress *addr,
147                                           jint timeout)
148 {
149   ::java::net::InetSocketAddress *tmp = (::java::net::InetSocketAddress*) addr;
150   ::java::net::InetAddress *host = tmp->getAddress();
151   if (! host)
152     throw new ::java::net::UnknownHostException(tmp->toString());
153
154   jint rport = tmp->getPort();
155         
156   // Set the SocketImpl's address and port fields before we try to
157   // connect.  Note that the fact that these are set doesn't imply
158   // that we're actually connected to anything.  We need to record
159   // this data before we attempt the connect, since non-blocking
160   // SocketChannels will use this and almost certainly throw timeout
161   // exceptions.
162   address = host;
163   port = rport;
164
165   union SockAddr u;
166   socklen_t addrlen = sizeof(u);
167   jbyteArray haddress = host->addr;
168   jbyte *bytes = elements (haddress);
169   int len = haddress->length;
170   struct sockaddr *ptr = (struct sockaddr *) &u.address;
171   if (len == 4)
172     {
173       u.address.sin_family = AF_INET;
174       memcpy (&u.address.sin_addr, bytes, len);
175       len = sizeof (struct sockaddr_in);
176       u.address.sin_port = htons (rport);
177     }
178 #ifdef HAVE_INET6
179   else if (len == 16)
180     {
181       u.address6.sin6_family = AF_INET6;
182       memcpy (&u.address6.sin6_addr, bytes, len);
183       len = sizeof (struct sockaddr_in6);
184       u.address6.sin6_port = htons (rport);
185     }
186 #endif
187   else
188     throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
189
190   if (timeout > 0)
191     {
192       int flags = ::fcntl (native_fd, F_GETFL);
193       ::fcntl (native_fd, F_SETFL, flags | O_NONBLOCK);
194       
195       if ((_Jv_connect (native_fd, ptr, len) != 0) && (errno != EINPROGRESS))
196         goto error;
197
198       fd_set fset;
199       struct timeval tv;
200       FD_ZERO(&fset);
201       FD_SET(native_fd, &fset);
202       tv.tv_sec = timeout / 1000;
203       tv.tv_usec = (timeout % 1000) * 1000;
204       int retval;
205       
206       if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0)
207         goto error;
208       else if (retval == 0)
209         throw new ::java::net::SocketTimeoutException
210           (JvNewStringUTF ("Connect timed out"));
211        // Set the socket back into a blocking state.
212        ::fcntl (native_fd, F_SETFL, flags);
213     }
214   else
215     {
216       if (_Jv_connect (native_fd, ptr, len) != 0)
217         goto error;
218     }
219
220   // A bind may not have been done on this socket; if so, set localport now.
221   if (localport == 0)
222     {
223       if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0)
224         localport = ntohs (u.address.sin_port);
225       else
226         goto error;
227     }
228
229   return;  
230
231  error:
232   char* strerr = strerror (errno);
233   throw new ::java::net::ConnectException (JvNewStringUTF (strerr));
234 }
235
236 void
237 gnu::java::net::PlainSocketImpl::listen (jint backlog)
238 {
239   if (::listen (native_fd, backlog) != 0)
240     {
241       char* strerr = strerror (errno);
242       throw new ::java::io::IOException (JvNewStringUTF (strerr));
243     }
244 }
245
246 static void 
247 throw_on_sock_closed (gnu::java::net::PlainSocketImpl *soc_impl)
248 {
249     // Avoid races from asynchronous close().
250     JvSynchronize sync (soc_impl);
251     if (soc_impl->native_fd == -1)
252       {
253         using namespace java::net;
254         // Socket was closed.
255         SocketException *se =
256             new SocketException (JvNewStringUTF ("Socket Closed"));
257         throw se;
258       }
259 }
260
261 void
262 gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *s)
263 {
264   union SockAddr u;
265   socklen_t addrlen = sizeof(u);
266   int new_socket = 0; 
267
268   // Do timeouts via select since SO_RCVTIMEO is not always available.
269   if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
270     {
271       fd_set fset;
272       struct timeval tv;
273       FD_ZERO(&fset);
274       FD_SET(native_fd, &fset);
275       tv.tv_sec = timeout / 1000;
276       tv.tv_usec = (timeout % 1000) * 1000;
277       int retval;
278       if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0)
279         goto error;
280       else if (retval == 0)
281         throw new ::java::net::SocketTimeoutException (
282                                           JvNewStringUTF("Accept timed out"));
283     }
284
285   new_socket = _Jv_accept (native_fd, (sockaddr*) &u, &addrlen);
286
287   if (new_socket < 0)
288     goto error;
289
290   jbyteArray raddr;
291   jint rport;
292   if (u.address.sin_family == AF_INET)
293     {
294       raddr = JvNewByteArray (4);
295       memcpy (elements (raddr), &u.address.sin_addr, 4);
296       rport = ntohs (u.address.sin_port);
297     }
298 #ifdef HAVE_INET6
299   else if (u.address.sin_family == AF_INET6)
300     {
301       raddr = JvNewByteArray (16);
302       memcpy (elements (raddr), &u.address6.sin6_addr, 16);
303       rport = ntohs (u.address6.sin6_port);
304     }
305 #endif
306   else
307     throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
308
309   s->native_fd = new_socket;
310   s->localport = localport;
311   s->address = ::java::net::InetAddress::getByAddress (raddr);
312   s->port = rport;
313   return;
314
315  error:
316   char* strerr = strerror (errno);
317   throw_on_sock_closed (this);
318   throw new ::java::io::IOException (JvNewStringUTF (strerr));
319 }
320
321 // Close(shutdown) the socket.
322 void
323 gnu::java::net::PlainSocketImpl::close()
324 {
325   // Avoid races from asynchronous finalization.
326   JvSynchronize sync (this);
327
328   // Should we use shutdown here? Yes.
329   // How would that effect so_linger? Uncertain.
330   ::shutdown (native_fd, 2);
331   // Ignore errors in shutdown as we are closing and all the same
332   // errors are handled in the close.
333   int res = _Jv_close (native_fd);
334
335   if (res == -1)
336     {
337       // These three errors are not errors according to tests performed
338       // on the reference implementation.
339       if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
340         throw new ::java::io::IOException  (JvNewStringUTF (strerror (errno)));
341     }
342   // Safe place to reset the file pointer.
343   native_fd = -1;
344   timeout = 0;
345 }
346
347 static void
348 write_helper (jint native_fd, jbyte *bytes, jint len);
349
350 // Write a byte to the socket.
351 void
352 gnu::java::net::PlainSocketImpl$SocketOutputStream::write(jint b)
353 {
354   jbyte data = (jbyte) b;
355   write_helper (this$0->native_fd, &data, 1);
356 }
357
358 // Write some bytes to the socket.
359 void
360 gnu::java::net::PlainSocketImpl$SocketOutputStream::write(jbyteArray b, jint offset, jint len)
361 {
362   if (! b)
363     throw new ::java::lang::NullPointerException;
364   if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
365     throw new ::java::lang::ArrayIndexOutOfBoundsException;
366
367   write_helper (this$0->native_fd, elements (b) + offset, len);
368 }
369
370 static void
371 write_helper(jint native_fd, jbyte *bytes, jint len)
372 {
373   int written = 0;
374
375   while (len > 0)
376     {
377       int r = _Jv_write (native_fd, bytes, len);
378
379       if (r == -1)
380         {
381           if (::java::lang::Thread::interrupted())
382             {
383               ::java::io::InterruptedIOException *iioe
384                 = new ::java::io::InterruptedIOException
385                 (JvNewStringLatin1 (strerror (errno)));
386               iioe->bytesTransferred = written;
387               throw iioe;
388             }
389           // Some errors should not cause exceptions.
390           if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF)
391             throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
392           break;
393         }
394
395       written += r;
396       len -= r;
397       bytes += r;
398     }
399 }
400
401 void
402 gnu::java::net::PlainSocketImpl::sendUrgentData (jint)
403 {
404   throw new ::java::net::SocketException (JvNewStringLatin1 (
405     "PlainSocketImpl: sending of urgent data not supported by this socket"));
406 }
407
408 static jint
409 read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
410              jbyte *bytes, jint count);
411
412 // Read a single byte from the socket.
413 jint
414 gnu::java::net::PlainSocketImpl$SocketInputStream::read(void)
415 {
416   jbyte data;
417
418   if (read_helper (this$0, &data, 1) == 1)
419     return data & 0xFF;
420
421   return -1;
422 }
423
424 // Read count bytes into the buffer, starting at offset.
425 jint
426 gnu::java::net::PlainSocketImpl$SocketInputStream::read(jbyteArray buffer,
427                                                         jint offset, 
428                                                         jint count)
429 {
430  if (! buffer)
431     throw new ::java::lang::NullPointerException;
432
433   jsize bsize = JvGetArrayLength (buffer);
434
435   if (offset < 0 || count < 0 || offset + count > bsize)
436     throw new ::java::lang::ArrayIndexOutOfBoundsException;
437
438   return read_helper (this$0, elements (buffer) + offset, count);
439 }
440
441 static jint
442 read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
443              jbyte *bytes, jint count)
444 {
445   // If zero bytes were requested, short circuit so that recv
446   // doesn't signal EOF.
447   if (count == 0)
448     return 0;
449     
450   // Do timeouts via select.
451   if (soc_impl->timeout > 0
452       && soc_impl->native_fd >= 0
453       && soc_impl->native_fd < FD_SETSIZE)
454     {
455       // Create the file descriptor set.
456       fd_set read_fds;
457       FD_ZERO (&read_fds);
458       FD_SET (soc_impl->native_fd, &read_fds);
459       // Create the timeout struct based on our internal timeout value.
460       struct timeval timeout_value;
461       timeout_value.tv_sec = soc_impl->timeout / 1000;
462       timeout_value.tv_usec =(soc_impl->timeout % 1000) * 1000;
463       // Select on the fds.
464       int sel_retval =
465         _Jv_select (soc_impl->native_fd + 1,
466                     &read_fds, NULL, NULL, &timeout_value);
467       // We're only interested in the 0 return.
468       // error returns still require us to try to read 
469       // the socket to see what happened.
470       if (sel_retval == 0)
471         {
472           ::java::net::SocketTimeoutException *timeoutException =
473             new ::java::net::SocketTimeoutException
474             (JvNewStringUTF ("Read timed out"));
475           throw timeoutException;
476         }
477     }
478
479   // Read the socket.
480   int r = ::recv (soc_impl->native_fd, (char *) bytes, count, 0);
481
482   if (r == 0)
483     {
484       throw_on_sock_closed (soc_impl);
485       return -1;
486     }
487
488   if (::java::lang::Thread::interrupted())
489     {
490       ::java::io::InterruptedIOException *iioe =
491         new ::java::io::InterruptedIOException
492         (JvNewStringUTF ("Read interrupted"));
493       iioe->bytesTransferred = r == -1 ? 0 : r;
494       throw iioe;
495     }
496   else if (r == -1)
497     {
498       throw_on_sock_closed (soc_impl);
499       // Some errors cause us to return end of stream...
500       if (errno == ENOTCONN)
501         return -1;
502
503       // Other errors need to be signalled.
504       throw new ::java::io::IOException (JvNewStringUTF (strerror (errno)));
505     }
506
507   return r;
508 }
509
510 // How many bytes are available?
511 jint
512 gnu::java::net::PlainSocketImpl::available(void)
513 {
514 #if defined(FIONREAD) || defined(HAVE_SELECT)
515   int num = 0;
516   int r = 0;
517   bool num_set = false;
518
519 #if defined(FIONREAD)
520   r = ::ioctl (native_fd, FIONREAD, &num);
521
522   if (r == -1 && errno == ENOTTY)
523     {
524       // If the ioctl doesn't work, we don't care.
525       r = 0;
526       num = 0;
527     }
528   else
529     num_set = true;
530 #elif defined(HAVE_SELECT)
531   if (native_fd < 0)
532     {
533       errno = EBADF;
534       r = -1;
535     }
536 #endif
537
538   if (r == -1)
539     {
540     posix_error:
541       throw new ::java::io::IOException(JvNewStringUTF(strerror(errno)));
542     }
543
544   // If we didn't get anything we can use select.
545
546 #if defined(HAVE_SELECT)
547   if (! num_set)
548     if (! num_set && native_fd >= 0 && native_fd < FD_SETSIZE)
549       {
550         fd_set rd;
551         FD_ZERO (&rd);
552         FD_SET (native_fd, &rd);
553         struct timeval tv;
554         tv.tv_sec = 0;
555         tv.tv_usec = 0;
556         r = _Jv_select (native_fd + 1, &rd, NULL, NULL, &tv);
557         if(r == -1)
558           goto posix_error;
559         num = r == 0 ? 0 : 1;
560       }
561 #endif /* HAVE_SELECT */
562
563   return (jint) num;
564 #else
565   throw new ::java::io::IOException (JvNewStringUTF ("unimplemented"));
566 #endif
567 }
568
569 void
570 gnu::java::net::PlainSocketImpl::setOption (jint optID, ::java::lang::Object *value)
571 {
572   int val;
573   socklen_t val_len = sizeof (val);
574
575   if (native_fd < 0)
576     throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
577
578   if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
579     {
580       ::java::lang::Boolean *boolobj = 
581         static_cast< ::java::lang::Boolean *> (value);
582       if (boolobj->booleanValue())
583         val = 1; 
584       else 
585         {
586           if (optID == _Jv_SO_LINGER_)
587             val = -1;
588           else
589             val = 0;
590         }
591     }
592   else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
593     {
594       ::java::lang::Integer *intobj = 
595         static_cast< ::java::lang::Integer *> (value);          
596       val = (int) intobj->intValue();
597     }
598   else
599     {
600       throw new ::java::lang::IllegalArgumentException (
601         JvNewStringLatin1 ("`value' must be Boolean or Integer"));
602     }
603
604   switch (optID) 
605     {
606       case _Jv_TCP_NODELAY_ :
607 #ifdef TCP_NODELAY
608         if (::setsockopt (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
609                           val_len) != 0)
610           goto error;
611 #else
612         throw new ::java::lang::InternalError
613           (JvNewStringUTF ("TCP_NODELAY not supported"));
614 #endif /* TCP_NODELAY */
615         return;
616
617       case _Jv_SO_KEEPALIVE_ :
618         if (::setsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
619                           val_len) != 0)
620           goto error;
621         return;
622       
623       case _Jv_SO_BROADCAST_ :
624         throw new ::java::net::SocketException
625           (JvNewStringUTF ("SO_BROADCAST not valid for TCP"));
626         return;
627         
628       case _Jv_SO_OOBINLINE_ :
629         if (::setsockopt (native_fd, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
630                           val_len) != 0)
631           goto error;
632         return;
633
634       case _Jv_SO_LINGER_ :
635 #ifdef SO_LINGER
636         struct linger l_val;
637         l_val.l_onoff = (val != -1);
638         l_val.l_linger = val;
639
640         if (::setsockopt (native_fd, SOL_SOCKET, SO_LINGER, (char *) &l_val,
641                           sizeof(l_val)) != 0)
642           goto error;    
643 #else
644         throw new ::java::lang::InternalError (
645           JvNewStringUTF ("SO_LINGER not supported"));
646 #endif /* SO_LINGER */
647         return;
648
649       case _Jv_SO_SNDBUF_ :
650       case _Jv_SO_RCVBUF_ :
651 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
652         int opt;
653         optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
654         if (::setsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
655           goto error;    
656 #else
657         throw new ::java::lang::InternalError (
658           JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
659 #endif 
660         return;
661
662       case _Jv_SO_BINDADDR_ :
663         throw new ::java::net::SocketException (
664           JvNewStringUTF ("SO_BINDADDR: read only option"));
665         return;
666
667       case _Jv_IP_MULTICAST_IF_ :
668         throw new ::java::net::SocketException (
669           JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
670         return;
671         
672       case _Jv_IP_MULTICAST_IF2_ :
673         throw new ::java::net::SocketException (
674           JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
675         return;
676         
677       case _Jv_IP_MULTICAST_LOOP_ :
678         throw new ::java::net::SocketException (
679           JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
680         return;
681         
682       case _Jv_IP_TOS_ :
683         if (::setsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
684                           val_len) != 0)
685           goto error;    
686         return;
687         
688       case _Jv_SO_REUSEADDR_ :
689 #if defined(SO_REUSEADDR)
690         if (::setsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
691             val_len) != 0)
692           goto error;
693         return;
694 #else
695         throw new ::java::lang::InternalError (
696           JvNewStringUTF ("SO_REUSEADDR not supported"));
697 #endif 
698
699       case _Jv_SO_TIMEOUT_ :
700         timeout = val;
701         return;
702
703       default :
704         errno = ENOPROTOOPT;
705     }
706
707  error:
708   char* strerr = strerror (errno);
709   throw new ::java::net::SocketException (JvNewStringUTF (strerr));
710 }
711
712 ::java::lang::Object *
713 gnu::java::net::PlainSocketImpl::getOption (jint optID)
714 {
715   int val;
716   socklen_t val_len = sizeof(val);
717   union SockAddr u;
718   socklen_t addrlen = sizeof(u);
719   struct linger l_val;
720   socklen_t l_val_len = sizeof(l_val);
721
722   switch (optID)
723     {
724 #ifdef TCP_NODELAY
725     case _Jv_TCP_NODELAY_ :
726       if (::getsockopt (native_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
727                         &val_len) != 0)
728         goto error;
729       else
730         return new ::java::lang::Boolean (val != 0);
731 #else
732       throw new ::java::lang::InternalError
733         (JvNewStringUTF ("TCP_NODELAY not supported"));
734 #endif       
735       break;
736       
737     case _Jv_SO_LINGER_ :
738 #ifdef SO_LINGER
739       if (::getsockopt (native_fd, SOL_SOCKET, SO_LINGER, (char *) &l_val,
740                         &l_val_len) != 0)
741         goto error;    
742  
743       if (l_val.l_onoff)
744         return new ::java::lang::Integer (l_val.l_linger);
745       else
746         return new ::java::lang::Boolean ((jboolean)false);
747 #else
748       throw new ::java::lang::InternalError
749         (JvNewStringUTF ("SO_LINGER not supported"));
750 #endif
751       break;    
752
753     case _Jv_SO_KEEPALIVE_ :
754       if (::getsockopt (native_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
755                         &val_len) != 0)
756         goto error;
757       else
758         return new ::java::lang::Boolean (val != 0);
759
760     case _Jv_SO_BROADCAST_ :
761       if (::getsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &val,
762                         &val_len) != 0)
763         goto error;    
764       return new ::java::lang::Boolean ((jboolean)val);
765         
766     case _Jv_SO_OOBINLINE_ :
767       if (::getsockopt (native_fd, SOL_SOCKET, SO_OOBINLINE, (char *) &val,
768                         &val_len) != 0)
769         goto error;    
770       return new ::java::lang::Boolean ((jboolean)val);
771         
772     case _Jv_SO_RCVBUF_ :
773     case _Jv_SO_SNDBUF_ :
774 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
775       int opt;
776       optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
777       if (::getsockopt (native_fd, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
778         goto error;    
779       else
780         return new ::java::lang::Integer (val);
781 #else
782       throw new ::java::lang::InternalError
783         (JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
784 #endif    
785       break;
786     case _Jv_SO_BINDADDR_:
787       // cache the local address 
788       if (localAddress == NULL)
789         {
790           jbyteArray laddr;
791
792           if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != 0)
793             goto error;
794
795           if (u.address.sin_family == AF_INET)
796             {
797               laddr = JvNewByteArray (4);
798               memcpy (elements (laddr), &u.address.sin_addr, 4);
799             }
800 #ifdef HAVE_INET6
801           else if (u.address.sin_family == AF_INET6)
802             {
803               laddr = JvNewByteArray (16);
804               memcpy (elements (laddr), &u.address6.sin6_addr, 16);
805             }
806 #endif
807           else
808             throw new ::java::net::SocketException
809               (JvNewStringUTF ("invalid family"));
810           localAddress = ::java::net::InetAddress::getByAddress (laddr);
811         }
812
813       return localAddress;
814       break;
815     case _Jv_IP_MULTICAST_IF_ :
816       throw new ::java::net::SocketException
817         (JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP"));
818       break;
819         
820     case _Jv_IP_MULTICAST_IF2_ :
821       throw new ::java::net::SocketException
822         (JvNewStringUTF ("IP_MULTICAST_IF2: not valid for TCP"));
823       break;
824         
825     case _Jv_IP_MULTICAST_LOOP_ :
826       throw new ::java::net::SocketException
827         (JvNewStringUTF ("IP_MULTICAST_LOOP: not valid for TCP"));
828       break;
829         
830     case _Jv_IP_TOS_ :
831       if (::getsockopt (native_fd, SOL_SOCKET, IP_TOS, (char *) &val,
832                         &val_len) != 0)
833         goto error;
834       return new ::java::lang::Integer (val);
835       break;
836         
837     case _Jv_SO_REUSEADDR_ :
838 #if defined(SO_REUSEADDR)
839       if (::getsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
840                         &val_len) != 0)
841         goto error;    
842 #else
843         throw new ::java::lang::InternalError (
844           JvNewStringUTF ("SO_REUSEADDR not supported"));
845 #endif 
846       break;
847
848     case _Jv_SO_TIMEOUT_ :
849       return new ::java::lang::Integer (timeout);
850       break;
851
852     default :
853       errno = ENOPROTOOPT;
854     }
855
856  error:
857   char* strerr = strerror (errno);
858   throw new ::java::net::SocketException (JvNewStringUTF (strerr));
859 }
860
861 void
862 gnu::java::net::PlainSocketImpl::shutdownInput (void)
863 {
864   if (::shutdown (native_fd, 0))
865     throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));
866 }
867
868 void
869 gnu::java::net::PlainSocketImpl::shutdownOutput (void)
870 {
871   if (::shutdown (native_fd, 1))
872     throw new ::java::net::SocketException (JvNewStringUTF (strerror (errno)));
873 }