source: trunk/src/gcc/libjava/java/net/natPlainSocketImpl.cc@ 680

Last change on this file since 680 was 2, checked in by bird, 23 years ago

Initial revision

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