OSDN Git Service

2003-09-10 Jeffrey D. Oldham <oldham@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / libjava / gnu / java / net / natPlainDatagramSocketImplPosix.cc
1 /* Copyright (C) 2003  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_NETINET_IN_H
13 #include <netinet/in.h>
14 #endif
15 #ifdef HAVE_ARPA_INET_H
16 #include <arpa/inet.h>
17 #endif
18 #include <errno.h>
19 #include <string.h>
20
21 #if HAVE_BSTRING_H
22 // Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2 
23 #include <bstring.h>
24 #endif
25
26 #include <gcj/cni.h>
27 #include <gnu/java/net/PlainDatagramSocketImpl.h>
28 #include <java/io/IOException.h>
29 #include <java/io/InterruptedIOException.h>
30 #include <java/net/BindException.h>
31 #include <java/net/SocketException.h>
32 #include <java/net/InetAddress.h>
33 #include <java/net/NetworkInterface.h>
34 #include <java/net/DatagramPacket.h>
35 #include <java/net/PortUnreachableException.h>
36 #include <java/lang/InternalError.h>
37 #include <java/lang/Object.h>
38 #include <java/lang/Boolean.h>
39 #include <java/lang/Integer.h>
40
41 union SockAddr
42 {
43   struct sockaddr_in address;
44 #ifdef HAVE_INET6
45   struct sockaddr_in6 address6;
46 #endif
47 };
48
49 union McastReq
50 {
51 #if HAVE_STRUCT_IP_MREQ
52   struct ip_mreq mreq;
53 #endif
54 #if HAVE_STRUCT_IPV6_MREQ
55   struct ipv6_mreq mreq6;
56 #endif
57 };
58
59 union InAddr
60 {
61   struct in_addr addr;
62 #ifdef HAVE_INET6
63   struct in6_addr addr6;
64 #endif
65 };
66
67
68 // FIXME: routines here and/or in natPlainSocketImpl.cc could throw
69 // NoRouteToHostException; also consider UnknownHostException, ConnectException.
70
71 void
72 gnu::java::net::PlainDatagramSocketImpl::create ()
73 {
74   int sock = _Jv_socket (AF_INET, SOCK_DGRAM, 0);
75
76   if (sock < 0)
77     {
78       char* strerr = strerror (errno);
79       throw new ::java::net::SocketException (JvNewStringUTF (strerr));
80     }
81
82   _Jv_platform_close_on_exec (sock);
83
84   // We use fnum in place of fd here.  From leaving fd null we avoid
85   // the double close problem in FileDescriptor.finalize.
86   fnum = sock;
87 }
88
89 void
90 gnu::java::net::PlainDatagramSocketImpl::bind (jint lport,
91                                                ::java::net::InetAddress *host)
92 {
93   union SockAddr u;
94   struct sockaddr *ptr = (struct sockaddr *) &u.address;
95   // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4.
96   jbyteArray haddress = host->addr;
97   jbyte *bytes = elements (haddress);
98   int len = haddress->length;
99
100   if (len == 4)
101     {
102       u.address.sin_family = AF_INET;
103
104       if (host != NULL)
105         memcpy (&u.address.sin_addr, bytes, len);
106       else
107         u.address.sin_addr.s_addr = htonl (INADDR_ANY);
108
109       len = sizeof (struct sockaddr_in);
110       u.address.sin_port = htons (lport);
111     }
112 #ifdef HAVE_INET6
113   else if (len == 16)
114     {
115       u.address6.sin6_family = AF_INET6;
116       memcpy (&u.address6.sin6_addr, bytes, len);
117       len = sizeof (struct sockaddr_in6);
118       u.address6.sin6_port = htons (lport);
119     }
120 #endif
121   else
122     throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
123
124   if (_Jv_bind (fnum, ptr, len) == 0)
125     {
126       socklen_t addrlen = sizeof(u);
127
128       if (lport != 0)
129         localPort = lport;
130       else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0)
131         localPort = ntohs (u.address.sin_port);
132       else
133         goto error;
134
135       /* Allow broadcast by default. */
136       int broadcast = 1;
137       if (::setsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast, 
138                         sizeof (broadcast)) != 0)
139         goto error;
140
141       return;
142     }
143
144  error:
145   char* strerr = strerror (errno);
146   throw new ::java::net::BindException (JvNewStringUTF (strerr));
147 }
148
149 void
150 gnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress *, jint)
151
152   throw new ::java::lang::InternalError (JvNewStringLatin1 (
153             "PlainDatagramSocketImpl::connect: not implemented yet"));
154 }
155
156 void
157 gnu::java::net::PlainDatagramSocketImpl::disconnect ()
158 {
159   throw new ::java::lang::InternalError (JvNewStringLatin1 (
160             "PlainDatagramSocketImpl::disconnect: not implemented yet"));
161 }
162
163 jint
164 gnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress *i)
165 {
166   // FIXME: Deal with Multicast and if the socket is connected.
167   union SockAddr u;
168   socklen_t addrlen = sizeof(u);
169   ssize_t retlen =
170     ::recvfrom (fnum, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u,
171       &addrlen);
172   if (retlen < 0)
173     goto error;
174   // FIXME: Deal with Multicast addressing and if the socket is connected.
175   jbyteArray raddr;
176   jint rport;
177   if (u.address.sin_family == AF_INET)
178     {
179       raddr = JvNewByteArray (4);
180       memcpy (elements (raddr), &u.address.sin_addr, 4);
181       rport = ntohs (u.address.sin_port);
182     }
183 #ifdef HAVE_INET6
184   else if (u.address.sin_family == AF_INET6)
185     {
186       raddr = JvNewByteArray (16);
187       memcpy (elements (raddr), &u.address6.sin6_addr, 16);
188       rport = ntohs (u.address6.sin6_port);
189     }
190 #endif
191   else
192     throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
193
194   i->addr = raddr;
195   return rport;
196  error:
197   char* strerr = strerror (errno);
198
199   if (errno == ECONNREFUSED)
200     throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
201
202   throw new ::java::io::IOException (JvNewStringUTF (strerr));
203 }
204
205 jint
206 gnu::java::net::PlainDatagramSocketImpl::peekData (::java::net::DatagramPacket *p)
207 {
208   // FIXME: Deal with Multicast and if the socket is connected.
209   union SockAddr u;
210   socklen_t addrlen = sizeof(u);
211   jbyte *dbytes = elements (p->getData());
212   ssize_t retlen = 0;
213
214   // Do timeouts via select since SO_RCVTIMEO is not always available.
215   if (timeout > 0 && fnum >= 0 && fnum < FD_SETSIZE)
216     {
217       fd_set rset;
218       struct timeval tv;
219       FD_ZERO(&rset);
220       FD_SET(fnum, &rset);
221       tv.tv_sec = timeout / 1000;
222       tv.tv_usec = (timeout % 1000) * 1000;
223       int retval;
224       if ((retval = _Jv_select (fnum + 1, &rset, NULL, NULL, &tv)) < 0)
225         goto error;
226       else if (retval == 0)
227         throw new ::java::io::InterruptedIOException ();
228     }
229
230   retlen =
231     ::recvfrom (fnum, (char *) dbytes, p->getLength(), MSG_PEEK, (sockaddr*) &u,
232       &addrlen);
233   if (retlen < 0)
234     goto error;
235   // FIXME: Deal with Multicast addressing and if the socket is connected.
236   jbyteArray raddr;
237   jint rport;
238   if (u.address.sin_family == AF_INET)
239     {
240       raddr = JvNewByteArray (4);
241       memcpy (elements (raddr), &u.address.sin_addr, 4);
242       rport = ntohs (u.address.sin_port);
243     }
244 #ifdef HAVE_INET6
245   else if (u.address.sin_family == AF_INET6)
246     {
247       raddr = JvNewByteArray (16);
248       memcpy (elements (raddr), &u.address6.sin6_addr, 16);
249       rport = ntohs (u.address6.sin6_port);
250     }
251 #endif
252   else
253     throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
254
255   p->setAddress (new ::java::net::InetAddress (raddr, NULL));
256   p->setPort (rport);
257   p->setLength ((jint) retlen);
258   return rport;
259
260  error:
261   char* strerr = strerror (errno);
262
263   if (errno == ECONNREFUSED)
264     throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
265
266   throw new ::java::io::IOException (JvNewStringUTF (strerr));
267 }
268
269 // Close(shutdown) the socket.
270 void
271 gnu::java::net::PlainDatagramSocketImpl::close ()
272 {
273   // Avoid races from asynchronous finalization.
274   JvSynchronize sync (this);
275
276   // The method isn't declared to throw anything, so we disregard
277   // the return value.
278   _Jv_close (fnum);
279   fnum = -1;
280   timeout = 0;
281 }
282
283 void
284 gnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket *p)
285 {
286   // FIXME: Deal with Multicast and if the socket is connected.
287   jint rport = p->getPort();
288   union SockAddr u;
289   jbyteArray haddress = p->getAddress()->addr;
290   jbyte *bytes = elements (haddress);
291   int len = haddress->length;
292   struct sockaddr *ptr = (struct sockaddr *) &u.address;
293   jbyte *dbytes = elements (p->getData());
294   if (len == 4)
295     {
296       u.address.sin_family = AF_INET;
297       memcpy (&u.address.sin_addr, bytes, len);
298       len = sizeof (struct sockaddr_in);
299       u.address.sin_port = htons (rport);
300     }
301 #ifdef HAVE_INET6
302   else if (len == 16)
303     {
304       u.address6.sin6_family = AF_INET6;
305       memcpy (&u.address6.sin6_addr, bytes, len);
306       len = sizeof (struct sockaddr_in6);
307       u.address6.sin6_port = htons (rport);
308     }
309 #endif
310   else
311     throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
312
313   if (::sendto (fnum, (char *) dbytes, p->getLength(), 0, ptr, len) >= 0)
314     return;
315
316   char* strerr = strerror (errno);
317
318   if (errno == ECONNREFUSED)
319     throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
320
321   throw new ::java::io::IOException (JvNewStringUTF (strerr));
322 }
323
324 void
325 gnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket *p)
326 {
327   // FIXME: Deal with Multicast and if the socket is connected.
328   union SockAddr u;
329   socklen_t addrlen = sizeof(u);
330   jbyte *dbytes = elements (p->getData());
331   ssize_t retlen = 0;
332
333   // Do timeouts via select since SO_RCVTIMEO is not always available.
334   if (timeout > 0 && fnum >= 0 && fnum < FD_SETSIZE)
335     {
336       fd_set rset;
337       struct timeval tv;
338       FD_ZERO(&rset);
339       FD_SET(fnum, &rset);
340       tv.tv_sec = timeout / 1000;
341       tv.tv_usec = (timeout % 1000) * 1000;
342       int retval;
343       if ((retval = _Jv_select (fnum + 1, &rset, NULL, NULL, &tv)) < 0)
344         goto error;
345       else if (retval == 0)
346         throw new ::java::io::InterruptedIOException ();
347     }
348
349   retlen =
350     ::recvfrom (fnum, (char *) dbytes, p->getLength(), 0, (sockaddr*) &u,
351       &addrlen);
352   if (retlen < 0)
353     goto error;
354   // FIXME: Deal with Multicast addressing and if the socket is connected.
355   jbyteArray raddr;
356   jint rport;
357   if (u.address.sin_family == AF_INET)
358     {
359       raddr = JvNewByteArray (4);
360       memcpy (elements (raddr), &u.address.sin_addr, 4);
361       rport = ntohs (u.address.sin_port);
362     }
363 #ifdef HAVE_INET6
364   else if (u.address.sin_family == AF_INET6)
365     {
366       raddr = JvNewByteArray (16);
367       memcpy (elements (raddr), &u.address6.sin6_addr, 16);
368       rport = ntohs (u.address6.sin6_port);
369     }
370 #endif
371   else
372     throw new ::java::net::SocketException (JvNewStringUTF ("invalid family"));
373
374   p->setAddress (new ::java::net::InetAddress (raddr, NULL));
375   p->setPort (rport);
376   p->setLength ((jint) retlen);
377   return;
378
379  error:
380   char* strerr = strerror (errno);
381
382   if (errno == ECONNREFUSED)
383     throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr));
384
385   throw new ::java::io::IOException (JvNewStringUTF (strerr));
386 }
387
388 void
389 gnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl)
390 {
391   // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
392   char val = (char) ttl;
393   socklen_t val_len = sizeof(val);
394
395   if (::setsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, val_len) == 0)
396     return;
397
398   char* strerr = strerror (errno);
399   throw new ::java::io::IOException (JvNewStringUTF (strerr));
400 }
401
402 jint
403 gnu::java::net::PlainDatagramSocketImpl::getTimeToLive ()
404 {
405   // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4.
406   char val;
407   socklen_t val_len = sizeof(val);
408
409   if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_TTL, &val, &val_len) == 0)
410     return ((int) val) & 0xFF;
411
412   char* strerr = strerror (errno);
413   throw new ::java::io::IOException (JvNewStringUTF (strerr));
414 }
415
416 void
417 gnu::java::net::PlainDatagramSocketImpl::mcastGrp (::java::net::InetAddress *inetaddr,
418                                                    ::java::net::NetworkInterface *,
419                                                    jboolean join)
420 {
421   // FIXME: implement use of NetworkInterface
422
423   union McastReq u;
424   jbyteArray haddress = inetaddr->addr;
425   jbyte *bytes = elements (haddress);
426   int len = haddress->length;
427   int level, opname;
428   const char *ptr;
429   if (0)
430     ;
431 #if HAVE_STRUCT_IP_MREQ
432   else if (len == 4)
433     {
434       level = IPPROTO_IP;
435       opname = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
436       memcpy (&u.mreq.imr_multiaddr, bytes, len);
437       // FIXME:  If a non-default interface is set, use it; see Stevens p. 501.
438       // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
439       u.mreq.imr_interface.s_addr = htonl (INADDR_ANY); 
440       len = sizeof (struct ip_mreq);
441       ptr = (const char *) &u.mreq;
442     }
443 #endif
444 #if HAVE_STRUCT_IPV6_MREQ
445   else if (len == 16)
446     {
447       level = IPPROTO_IPV6;
448
449       /* Prefer new RFC 2553 names.  */
450 #ifndef IPV6_JOIN_GROUP
451 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
452 #endif
453 #ifndef IPV6_LEAVE_GROUP
454 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
455 #endif
456
457       opname = join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP;
458       memcpy (&u.mreq6.ipv6mr_multiaddr, bytes, len);
459       // FIXME:  If a non-default interface is set, use it; see Stevens p. 501.
460       // Maybe not, see note in last paragraph at bottom of Stevens p. 497.
461       u.mreq6.ipv6mr_interface = 0;
462       len = sizeof (struct ipv6_mreq);
463       ptr = (const char *) &u.mreq6;
464     }
465 #endif
466   else
467     throw new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
468
469   if (::setsockopt (fnum, level, opname, ptr, len) == 0)
470     return;
471
472   char* strerr = strerror (errno);
473   throw new ::java::io::IOException (JvNewStringUTF (strerr));
474 }
475
476 void
477 gnu::java::net::PlainDatagramSocketImpl::setOption (jint optID,
478                                                     ::java::lang::Object *value)
479 {
480   int val;
481   socklen_t val_len = sizeof (val);
482
483   if (fnum < 0)
484     throw new ::java::net::SocketException (JvNewStringUTF ("Socket closed"));
485
486   if (_Jv_IsInstanceOf (value, &::java::lang::Boolean::class$))
487     {
488       ::java::lang::Boolean *boolobj = 
489         static_cast< ::java::lang::Boolean *> (value);
490       val = boolobj->booleanValue() ? 1 : 0;
491     }
492   else if (_Jv_IsInstanceOf (value, &::java::lang::Integer::class$))
493     {
494       ::java::lang::Integer *intobj = 
495         static_cast< ::java::lang::Integer *> (value);          
496       val = (int) intobj->intValue();
497     }
498   // Else assume value to be an InetAddress for use with IP_MULTICAST_IF.
499
500   switch (optID) 
501     {
502       case _Jv_TCP_NODELAY_ :
503         throw new ::java::net::SocketException (
504           JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
505         return;
506       case _Jv_SO_LINGER_ :
507         throw new ::java::net::SocketException (
508           JvNewStringUTF ("SO_LINGER not valid for UDP"));
509         return;
510       case _Jv_SO_KEEPALIVE_ :
511         throw new ::java::net::SocketException (
512           JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
513         return;
514
515       case _Jv_SO_BROADCAST_ :
516         if (::setsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
517                           val_len) != 0)
518           goto error;
519         break;
520         
521       case _Jv_SO_OOBINLINE_ :
522         throw new ::java::net::SocketException (
523           JvNewStringUTF ("SO_OOBINLINE: not valid for UDP"));
524         break;
525         
526       case _Jv_SO_SNDBUF_ :
527       case _Jv_SO_RCVBUF_ :
528 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
529         int opt;
530         optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
531         if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
532           goto error;    
533 #else
534         throw new ::java::lang::InternalError (
535           JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
536 #endif 
537         return;
538       case _Jv_SO_REUSEADDR_ :
539 #if defined(SO_REUSEADDR)
540         if (::setsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
541             val_len) != 0)
542           goto error;
543 #else
544         throw new ::java::lang::InternalError (
545           JvNewStringUTF ("SO_REUSEADDR not supported"));
546 #endif 
547         return;
548       case _Jv_SO_BINDADDR_ :
549         throw new ::java::net::SocketException (
550           JvNewStringUTF ("SO_BINDADDR: read only option"));
551         return;
552       case _Jv_IP_MULTICAST_IF_ :
553         union InAddr u;
554         jbyteArray haddress;
555         jbyte *bytes;
556         int len;
557         int level, opname;
558         const char *ptr;
559
560         haddress = ((::java::net::InetAddress *) value)->addr;
561         bytes = elements (haddress);
562         len = haddress->length;
563         if (len == 4)
564           {
565             level = IPPROTO_IP;
566             opname = IP_MULTICAST_IF;
567             memcpy (&u.addr, bytes, len);
568             len = sizeof (struct in_addr);
569             ptr = (const char *) &u.addr;
570           }
571 // Tru64 UNIX V5.0 has struct sockaddr_in6, but no IPV6_MULTICAST_IF
572 #if defined (HAVE_INET6) && defined (IPV6_MULTICAST_IF)
573         else if (len == 16)
574           {
575             level = IPPROTO_IPV6;
576             opname = IPV6_MULTICAST_IF;
577             memcpy (&u.addr6, bytes, len);
578             len = sizeof (struct in6_addr);
579             ptr = (const char *) &u.addr6;
580           }
581 #endif
582         else
583           throw
584             new ::java::net::SocketException (JvNewStringUTF ("invalid length"));
585
586         if (::setsockopt (fnum, level, opname, ptr, len) != 0)
587           goto error;
588         return;
589         
590       case _Jv_IP_MULTICAST_IF2_ :
591         throw new ::java::net::SocketException (
592           JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
593         break;
594         
595       case _Jv_IP_MULTICAST_LOOP_ :
596         throw new ::java::net::SocketException (
597           JvNewStringUTF ("IP_MULTICAST_LOOP: not yet implemented"));
598         break;
599         
600       case _Jv_IP_TOS_ :
601         if (::setsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
602            val_len) != 0)
603           goto error;    
604         return;
605         
606       case _Jv_SO_TIMEOUT_ :
607         timeout = val;
608         return;
609       default :
610         errno = ENOPROTOOPT;
611     }
612
613  error:
614   char* strerr = strerror (errno);
615   throw new ::java::net::SocketException (JvNewStringUTF (strerr));
616 }
617
618 ::java::lang::Object *
619 gnu::java::net::PlainDatagramSocketImpl::getOption (jint optID)
620 {
621   int val;
622   socklen_t val_len = sizeof(val);
623   union SockAddr u;
624   socklen_t addrlen = sizeof(u);
625
626   switch (optID)
627     {
628       case _Jv_TCP_NODELAY_ :
629         throw new ::java::net::SocketException (
630           JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
631         break;
632       case _Jv_SO_LINGER_ :
633         throw new ::java::net::SocketException (
634           JvNewStringUTF ("SO_LINGER not valid for UDP"));
635         break;    
636       case _Jv_SO_KEEPALIVE_ :
637         throw new ::java::net::SocketException (
638           JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
639         break;
640         
641       case _Jv_SO_BROADCAST_ :
642         if (::getsockopt (fnum, SOL_SOCKET, SO_BROADCAST, (char *) &val,
643             &val_len) != 0)
644           goto error;
645         return new ::java::lang::Boolean (val != 0);
646         
647       case _Jv_SO_OOBINLINE_ :
648         throw new ::java::net::SocketException (
649           JvNewStringUTF ("SO_OOBINLINE not valid for UDP"));
650         break;
651       
652       case _Jv_SO_RCVBUF_ :
653       case _Jv_SO_SNDBUF_ :
654 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
655         int opt;
656         optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
657         if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
658           goto error;    
659         else
660           return new ::java::lang::Integer (val);
661 #else
662         throw new ::java::lang::InternalError (
663           JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported"));
664 #endif    
665         break;
666       case _Jv_SO_BINDADDR_:
667         // cache the local address
668         if (localAddress == NULL)
669           {     
670             jbyteArray laddr;
671             if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
672               goto error;
673             if (u.address.sin_family == AF_INET)
674               {
675                 laddr = JvNewByteArray (4);
676                 memcpy (elements (laddr), &u.address.sin_addr, 4);
677               }
678 #ifdef HAVE_INET6
679             else if (u.address.sin_family == AF_INET6)
680               {
681                 laddr = JvNewByteArray (16);
682                 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
683               }
684 #endif
685             else
686               throw new ::java::net::SocketException (
687                               JvNewStringUTF ("invalid family"));
688             localAddress = new ::java::net::InetAddress (laddr, NULL);
689           }
690         return localAddress;  
691         break;
692       case _Jv_SO_REUSEADDR_ :
693 #if defined(SO_REUSEADDR)
694         if (::getsockopt (fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
695             &val_len) != 0)
696           goto error;
697         return new ::java::lang::Boolean (val != 0);
698 #else
699         throw new ::java::lang::InternalError (
700           JvNewStringUTF ("SO_REUSEADDR not supported"));
701 #endif 
702         break;
703       case _Jv_IP_MULTICAST_IF_ :
704 #ifdef HAVE_INET_NTOA
705         struct in_addr inaddr;
706         socklen_t inaddr_len;
707         char *bytes;
708
709         inaddr_len = sizeof(inaddr);
710         if (::getsockopt (fnum, IPPROTO_IP, IP_MULTICAST_IF, (char *) &inaddr,
711             &inaddr_len) != 0)
712           goto error;
713
714         bytes = inet_ntoa (inaddr);
715
716         return ::java::net::InetAddress::getByName (JvNewStringLatin1 (bytes));
717 #else
718         throw new ::java::net::SocketException (
719           JvNewStringUTF ("IP_MULTICAST_IF: not available - no inet_ntoa()"));
720 #endif
721         break;
722       case _Jv_SO_TIMEOUT_ :
723         return new ::java::lang::Integer (timeout);
724         break;
725         
726       case _Jv_IP_MULTICAST_IF2_ :
727         throw new ::java::net::SocketException (
728           JvNewStringUTF ("IP_MULTICAST_IF2: not yet implemented"));
729         break;
730         
731       case _Jv_IP_MULTICAST_LOOP_ :
732         if (::getsockopt (fnum, SOL_SOCKET, IP_MULTICAST_LOOP, (char *) &val,
733             &val_len) != 0)
734           goto error;
735         return new ::java::lang::Boolean (val != 0);
736         
737       case _Jv_IP_TOS_ :
738         if (::getsockopt (fnum, SOL_SOCKET, IP_TOS, (char *) &val,
739            &val_len) != 0)
740           goto error;
741         return new ::java::lang::Integer (val);
742         
743       default :
744         errno = ENOPROTOOPT;
745     }
746
747  error:
748   char* strerr = strerror (errno);
749   throw new ::java::net::SocketException (JvNewStringUTF (strerr));
750 }