Makefile.in: Rebuilt.
[gcc.git] / libjava / java / net / natPlainSocketImpl.cc
1 /* Copyright (C) 1998, 1999, 2000 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
11
12 #ifndef DISABLE_JAVA_NET
13 #ifdef USE_WINSOCK
14 #include <windows.h>
15 #include <winsock.h>
16 #include <errno.h>
17 #include <string.h>
18 #ifndef ENOPROTOOPT
19 #define ENOPROTOOPT 109
20 #endif
21 #else /* USE_WINSOCK */
22 #include "posix.h"
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <netinet/tcp.h>
26 #include <errno.h>
27 #include <string.h>
28 #endif /* USE_WINSOCK */
29 #endif /* DISABLE_JAVA_NET */
30
31 #if HAVE_BSTRING_H
32 // Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2
33 #include <bstring.h>
34 #endif
35
36 #include <gcj/cni.h>
37 #include <gcj/javaprims.h>
38 #include <java/io/IOException.h>
39 #include <java/io/FileDescriptor.h>
40 #include <java/io/InterruptedIOException.h>
41 #include <java/net/BindException.h>
42 #include <java/net/ConnectException.h>
43 #include <java/net/PlainSocketImpl.h>
44 #include <java/net/InetAddress.h>
45 #include <java/net/SocketException.h>
46 #include <java/lang/InternalError.h>
47 #include <java/lang/Object.h>
48 #include <java/lang/Boolean.h>
49 #include <java/lang/Class.h>
50 #include <java/lang/Integer.h>
51
52 #define BooleanClass _CL_Q34java4lang7Boolean
53 extern java::lang::Class BooleanClass;
54
55 #ifdef DISABLE_JAVA_NET
56
57 void
58 java::net::PlainSocketImpl::create (jboolean)
59 {
60 JvThrow (new java::io::IOException (JvNewStringLatin1 ("SocketImpl.create: unimplemented")));
61 }
62
63 void
64 java::net::PlainSocketImpl::bind (java::net::InetAddress *, jint)
65 {
66 JvThrow (new BindException (JvNewStringLatin1 ("SocketImpl.bind: unimplemented")));
67 }
68
69 void
70 java::net::PlainSocketImpl::connect (java::net::InetAddress *, jint)
71 {
72 JvThrow (new ConnectException (JvNewStringLatin1 ("SocketImpl.connect: unimplemented")));
73 }
74
75 void
76 java::net::PlainSocketImpl::listen (jint)
77 {
78 JvThrow (new java::io::IOException (JvNewStringLatin1 ("SocketImpl.listen: unimplemented")));
79 }
80
81 void
82 java::net::PlainSocketImpl::accept (java::net::PlainSocketImpl *)
83 {
84 JvThrow (new java::io::IOException (JvNewStringLatin1 ("SocketImpl.accept: unimplemented")));
85 }
86
87 void
88 java::net::PlainSocketImpl::setOption (jint, java::lang::Object *)
89 {
90 JvThrow (new SocketException (JvNewStringLatin1 ("SocketImpl.setOption: unimplemented")));
91 }
92
93 java::lang::Object *
94 java::net::PlainSocketImpl::getOption (jint)
95 {
96 JvThrow (new SocketException (JvNewStringLatin1 ("SocketImpl.getOption: unimplemented")));
97 }
98
99 #else /* DISABLE_JAVA_NET */
100
101 #ifndef HAVE_SOCKLEN_T
102 typedef int socklen_t;
103 #endif
104
105 union SockAddr
106 {
107 struct sockaddr_in address;
108 #ifdef HAVE_INET6
109 struct sockaddr_in6 address6;
110 #endif
111 };
112
113 void
114 java::net::PlainSocketImpl::create (jboolean stream)
115 {
116 int sock = ::socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
117 if (sock < 0)
118 {
119 char* strerr = strerror (errno);
120 JvThrow (new java::io::IOException (JvNewStringUTF (strerr)));
121 }
122 fnum = sock;
123 fd = new java::io::FileDescriptor (sock);
124 }
125
126 void
127 java::net::PlainSocketImpl::bind (java::net::InetAddress *host, jint lport)
128 {
129 union SockAddr u;
130 struct sockaddr *ptr = (struct sockaddr *) &u.address;
131 jbyteArray haddress = host->address;
132 jbyte *bytes = elements (haddress);
133 int len = haddress->length;
134 int i = 1;
135
136 if (len == 4)
137 {
138 u.address.sin_family = AF_INET;
139 if (host != NULL)
140 memcpy (&u.address.sin_addr, bytes, len);
141 else
142 u.address.sin_addr.s_addr = htonl (INADDR_ANY);
143 len = sizeof (struct sockaddr_in);
144 u.address.sin_port = htons (lport);
145 }
146 #ifdef HAVE_INET6
147 else if (len == 16)
148 {
149 u.address6.sin6_family = AF_INET6;
150 memcpy (&u.address6.sin6_addr, bytes, len);
151 len = sizeof (struct sockaddr_in6);
152 u.address6.sin6_port = htons (lport);
153 }
154 #endif
155 else
156 goto error;
157
158 // Enable SO_REUSEADDR, so that servers can reuse ports left in TIME_WAIT.
159 ::setsockopt(fnum, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof(i));
160
161 if (::bind (fnum, ptr, len) == 0)
162 {
163 address = host;
164 socklen_t addrlen = sizeof(u);
165 if (lport != 0)
166 localport = lport;
167 else if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0)
168 localport = ntohs (u.address.sin_port);
169 else
170 goto error;
171 return;
172 }
173 error:
174 char* strerr = strerror (errno);
175 JvThrow (new java::net::BindException (JvNewStringUTF (strerr)));
176 }
177
178 void
179 java::net::PlainSocketImpl::connect (java::net::InetAddress *host, jint rport)
180 {
181 union SockAddr u;
182 socklen_t addrlen = sizeof(u);
183 jbyteArray haddress = host->address;
184 jbyte *bytes = elements (haddress);
185 int len = haddress->length;
186 struct sockaddr *ptr = (struct sockaddr *) &u.address;
187 if (len == 4)
188 {
189 u.address.sin_family = AF_INET;
190 memcpy (&u.address.sin_addr, bytes, len);
191 len = sizeof (struct sockaddr_in);
192 u.address.sin_port = htons (rport);
193 }
194 #ifdef HAVE_INET6
195 else if (len == 16)
196 {
197 u.address6.sin6_family = AF_INET6;
198 memcpy (&u.address6.sin6_addr, bytes, len);
199 len = sizeof (struct sockaddr_in6);
200 u.address6.sin6_port = htons (rport);
201 }
202 #endif
203 else
204 goto error;
205 if (::connect (fnum, ptr, len) != 0)
206 goto error;
207 address = host;
208 port = rport;
209 // A bind may not have been done on this socket; if so, set localport now.
210 if (localport == 0)
211 if (::getsockname (fnum, (sockaddr*) &u, &addrlen) == 0)
212 localport = ntohs (u.address.sin_port);
213 else
214 goto error;
215 return;
216 error:
217 char* strerr = strerror (errno);
218 JvThrow (new java::net::ConnectException (JvNewStringUTF (strerr)));
219 }
220
221 void
222 java::net::PlainSocketImpl::listen (jint backlog)
223 {
224 if (::listen (fnum, backlog) != 0)
225 {
226 char* strerr = strerror (errno);
227 JvThrow (new java::io::IOException (JvNewStringUTF (strerr)));
228 }
229 }
230
231 void
232 java::net::PlainSocketImpl::accept (java::net::PlainSocketImpl *s)
233 {
234 union SockAddr u;
235 socklen_t addrlen = sizeof(u);
236 int new_socket = 0;
237
238 // Do timeouts via select since SO_RCVTIMEO is not always available.
239 if (timeout > 0)
240 {
241 fd_set rset;
242 struct timeval tv;
243 FD_ZERO(&rset);
244 FD_SET(fnum, &rset);
245 tv.tv_sec = timeout / 1000;
246 tv.tv_usec = (timeout % 1000) * 1000;
247 int retval;
248 if ((retval = _Jv_select (fnum + 1, &rset, NULL, NULL, &tv)) < 0)
249 goto error;
250 else if (retval == 0)
251 JvThrow (new java::io::InterruptedIOException (
252 JvNewStringUTF("Accept timed out")));
253 }
254
255 new_socket = ::accept (fnum, (sockaddr*) &u, &addrlen);
256 if (new_socket < 0)
257 goto error;
258 jbyteArray raddr;
259 jint rport;
260 if (u.address.sin_family == AF_INET)
261 {
262 raddr = JvNewByteArray (4);
263 memcpy (elements (raddr), &u.address.sin_addr, 4);
264 rport = ntohs (u.address.sin_port);
265 }
266 #ifdef HAVE_INET6
267 else if (u.address.sin_family == AF_INET6)
268 {
269 raddr = JvNewByteArray (16);
270 memcpy (elements (raddr), &u.address6.sin6_addr, 16);
271 rport = ntohs (u.address6.sin6_port);
272 }
273 #endif
274 else
275 goto error;
276 s->fnum = new_socket;
277 s->localport = localport;
278 s->address = new InetAddress (raddr, NULL);
279 s->port = rport;
280 s->fd = new java::io::FileDescriptor (new_socket);
281 return;
282 error:
283 char* strerr = strerror (errno);
284 JvThrow (new java::io::IOException (JvNewStringUTF (strerr)));
285 }
286
287 void
288 java::net::PlainSocketImpl::setOption (jint optID, java::lang::Object *value)
289 {
290 int val;
291 socklen_t val_len = sizeof (val);
292
293 if (_Jv_IsInstanceOf (value, &BooleanClass))
294 {
295 java::lang::Boolean *boolobj =
296 static_cast<java::lang::Boolean *> (value);
297 if (boolobj->booleanValue())
298 val = 1;
299 else
300 {
301 if (optID == _Jv_SO_LINGER_)
302 val = -1;
303 else
304 val = 0;
305 }
306 }
307 else // assume value is an Integer
308 {
309 java::lang::Integer *intobj =
310 static_cast<java::lang::Integer *> (value);
311 val = (int) intobj->intValue();
312 }
313
314 switch (optID)
315 {
316 case _Jv_TCP_NODELAY_ :
317 #ifdef TCP_NODELAY
318 if (::setsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
319 val_len) != 0)
320 goto error;
321 #else
322 JvThrow (new java::lang::InternalError (
323 JvNewStringUTF ("TCP_NODELAY not supported")));
324 #endif /* TCP_NODELAY */
325 return;
326 case _Jv_SO_LINGER_ :
327 #ifdef SO_LINGER
328 struct linger l_val;
329 l_val.l_onoff = (val != -1);
330 l_val.l_linger = val;
331 if (::setsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
332 sizeof(l_val)) != 0)
333 goto error;
334 #else
335 JvThrow (new java::lang::InternalError (
336 JvNewStringUTF ("SO_LINGER not supported")));
337 #endif /* SO_LINGER */
338 return;
339 case _Jv_SO_SNDBUF_ :
340 case _Jv_SO_RCVBUF_ :
341 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
342 int opt;
343 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
344 if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
345 goto error;
346 #else
347 JvThrow (new java::lang::InternalError (
348 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported")));
349 #endif
350 return;
351 case _Jv_SO_BINDADDR_ :
352 JvThrow (new java::net::SocketException (
353 JvNewStringUTF ("SO_BINDADDR: read only option")));
354 return;
355 case _Jv_IP_MULTICAST_IF_ :
356 JvThrow (new java::net::SocketException (
357 JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP")));
358 return;
359 case _Jv_SO_REUSEADDR_ :
360 JvThrow (new java::net::SocketException (
361 JvNewStringUTF ("SO_REUSEADDR: not valid for TCP")));
362 return;
363 case _Jv_SO_TIMEOUT_ :
364 timeout = val;
365 return;
366 default :
367 errno = ENOPROTOOPT;
368 }
369
370 error:
371 char* strerr = strerror (errno);
372 JvThrow (new java::net::SocketException (JvNewStringUTF (strerr)));
373 }
374
375 java::lang::Object *
376 java::net::PlainSocketImpl::getOption (jint optID)
377 {
378 int val;
379 socklen_t val_len = sizeof(val);
380 union SockAddr u;
381 socklen_t addrlen = sizeof(u);
382 struct linger l_val;
383 socklen_t l_val_len = sizeof(l_val);
384
385 switch (optID)
386 {
387 #ifdef TCP_NODELAY
388 case _Jv_TCP_NODELAY_ :
389 if (::getsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
390 &val_len) != 0)
391 goto error;
392 else
393 return new java::lang::Boolean (val != 0);
394 #else
395 JvThrow (new java::lang::InternalError (
396 JvNewStringUTF ("TCP_NODELAY not supported")));
397 #endif
398 break;
399
400 case _Jv_SO_LINGER_ :
401 #ifdef SO_LINGER
402 if (::getsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
403 &l_val_len) != 0)
404 goto error;
405 if (l_val.l_onoff)
406 return new java::lang::Integer (l_val.l_linger);
407 else
408 return new java::lang::Boolean ((__java_boolean)false);
409 #else
410 JvThrow (new java::lang::InternalError (
411 JvNewStringUTF ("SO_LINGER not supported")));
412 #endif
413 break;
414 case _Jv_SO_RCVBUF_ :
415 case _Jv_SO_SNDBUF_ :
416 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
417 int opt;
418 optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
419 if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
420 goto error;
421 else
422 return new java::lang::Integer (val);
423 #else
424 JvThrow (new java::lang::InternalError (
425 JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported")));
426 #endif
427 break;
428 case _Jv_SO_BINDADDR_:
429 // cache the local address
430 if (localAddress == NULL)
431 {
432 jbyteArray laddr;
433 if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
434 goto error;
435 if (u.address.sin_family == AF_INET)
436 {
437 laddr = JvNewByteArray (4);
438 memcpy (elements (laddr), &u.address.sin_addr, 4);
439 }
440 #ifdef HAVE_INET6
441 else if (u.address.sin_family == AF_INET6)
442 {
443 laddr = JvNewByteArray (16);
444 memcpy (elements (laddr), &u.address6.sin6_addr, 16);
445 }
446 #endif
447 else
448 goto error;
449 localAddress = new java::net::InetAddress (laddr, NULL);
450 }
451 return localAddress;
452 break;
453 case _Jv_IP_MULTICAST_IF_ :
454 JvThrow (new java::net::SocketException (
455 JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP")));
456 break;
457 case _Jv_SO_REUSEADDR_ :
458 JvThrow (new java::net::SocketException (
459 JvNewStringUTF ("SO_REUSEADDR: not valid for TCP")));
460 break;
461 case _Jv_SO_TIMEOUT_ :
462 return new java::lang::Integer (timeout);
463 break;
464 default :
465 errno = ENOPROTOOPT;
466 }
467
468 error:
469 char* strerr = strerror (errno);
470 JvThrow (new java::net::SocketException (JvNewStringUTF (strerr)));
471 }
472
473 #endif /* DISABLE_JAVA_NET */