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