Merge from mainline
[official-gcc.git] / libjava / classpath / native / jni / java-net / javanet.c
blob0f296a60479bfff5f74e524e9c2dbfde441fbc13
1 /* javanet.c - Common internal functions for the java.net package
2 Copyright (C) 1998, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 /* do not move; needed here because of some macro definitions */
39 #include <config.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
45 #include <jni.h>
46 #include <jcl.h>
48 #include "javanet.h"
50 #include "target_native.h"
51 #ifndef WITHOUT_NETWORK
52 #include "target_native_network.h"
53 #endif /* WITHOUT_NETWORK */
55 #ifndef WITHOUT_NETWORK
56 /* Need to have some value for SO_TIMEOUT */
57 #ifndef SO_TIMEOUT
58 #ifndef SO_RCVTIMEO
59 #warning Neither SO_TIMEOUT or SO_RCVTIMEO are defined!
60 #warning This will cause all get/setOption calls with that value to throw an exception
61 #else
62 #define SO_TIMEOUT SO_RCVTIMEO
63 #endif /* not SO_RCVTIMEO */
64 #endif /* not SO_TIMEOUT */
65 #endif /* WITHOUT_NETWORK */
67 /*************************************************************************/
70 * Sets an integer field in the specified object.
72 static void
73 _javanet_set_int_field (JNIEnv * env, jobject obj,
74 const char *class, const char *field, int val)
76 jclass cls;
77 jfieldID fid;
79 cls = (*env)->FindClass (env, class);
80 if (cls == NULL)
81 return;
83 fid = (*env)->GetFieldID (env, cls, field, "I");
84 if (fid == NULL)
85 return;
87 (*env)->SetIntField (env, obj, fid, val);
89 return;
92 /*************************************************************************/
95 * Returns the value of the specified integer instance variable field or
96 * -1 if an error occurs.
98 int
99 _javanet_get_int_field (JNIEnv * env, jobject obj, const char *field)
101 jclass cls = 0;
102 jfieldID fid;
103 int fd;
105 DBG ("_javanet_get_int_field(): Entered _javanet_get_int_field\n");
107 cls = (*env)->GetObjectClass (env, obj);
108 if (cls == NULL)
109 return -1;
111 fid = (*env)->GetFieldID (env, cls, field, "I");
112 if (fid == NULL)
113 return -1;
114 DBG ("_javanet_get_int_field(): Found field id\n");
116 fd = (*env)->GetIntField (env, obj, fid);
118 return fd;
121 /*************************************************************************/
124 * Creates a FileDescriptor object in the parent class. It is not used
125 * by this implementation, but the docs list it as a variable, so we
126 * need to include it.
128 static void
129 _javanet_create_localfd (JNIEnv * env, jobject this, jboolean stream)
131 jclass this_cls, fd_cls;
132 jfieldID fid;
133 jmethodID mid;
134 jobject fd_obj;
136 DBG ("_javanet_create_localfd(): Entered _javanet_create_localfd\n");
138 /* Look up the fd field */
139 if (stream)
140 this_cls = (*env)->FindClass(env, "java/net/SocketImpl");
141 else
142 this_cls = (*env)->FindClass(env, "java/net/DatagramSocketImpl");
143 if (this_cls == NULL)
144 return;
146 fid = (*env)->GetFieldID (env, this_cls, "fd", "Ljava/io/FileDescriptor;");
147 if (fid == NULL)
148 return;
150 DBG ("_javanet_create_localfd(): Found fd variable\n");
152 /* Create a FileDescriptor */
153 fd_cls = (*env)->FindClass (env, "java/io/FileDescriptor");
154 if (fd_cls == NULL)
155 return;
157 DBG ("_javanet_create_localfd(): Found FileDescriptor class\n");
159 mid = (*env)->GetMethodID (env, fd_cls, "<init>", "()V");
160 if (mid == NULL)
161 return;
163 DBG ("_javanet_create_localfd(): Found FileDescriptor constructor\n");
165 fd_obj = (*env)->NewObject (env, fd_cls, mid);
166 if (fd_obj == NULL)
167 return;
169 DBG ("_javanet_create_localfd(): Created FileDescriptor\n");
171 /* Now set the pointer to the new FileDescriptor */
172 (*env)->SetObjectField (env, this, fid, fd_obj);
173 DBG ("_javanet_create_localfd(): Set fd field\n");
175 return;
178 /*************************************************************************/
181 * Returns a Boolean object with the specfied value
183 static jobject
184 _javanet_create_boolean (JNIEnv * env, jboolean val)
186 jclass cls;
187 jmethodID mid;
188 jobject obj;
190 cls = (*env)->FindClass (env, "java/lang/Boolean");
191 if (cls == NULL)
192 return NULL;
194 mid = (*env)->GetMethodID (env, cls, "<init>", "(Z)V");
195 if (mid == NULL)
196 return NULL;
198 obj = (*env)->NewObject (env, cls, mid, val);
199 if (obj == NULL)
200 return NULL;
202 return obj;
205 /*************************************************************************/
208 * Returns an Integer object with the specfied value
210 static jobject
211 _javanet_create_integer (JNIEnv * env, jint val)
213 jclass cls;
214 jmethodID mid;
215 jobject obj;
217 cls = (*env)->FindClass (env, "java/lang/Integer");
218 if (cls == NULL)
219 return NULL;
221 mid = (*env)->GetMethodID (env, cls, "<init>", "(I)V");
222 if (mid == NULL)
223 return NULL;
225 obj = (*env)->NewObject (env, cls, mid, val);
226 if (obj == NULL)
227 return NULL;
229 return obj;
232 /*************************************************************************/
235 * Builds an InetAddress object from a 32 bit address in host byte order
237 static jobject
238 _javanet_create_inetaddress (JNIEnv * env, int netaddr)
240 #ifndef WITHOUT_NETWORK
241 unsigned char octets[4];
242 char buf[16];
243 jclass ia_cls;
244 jmethodID mid;
245 jstring ip_str;
246 jobject ia;
248 /* Build a string IP address */
249 TARGET_NATIVE_NETWORK_INT_TO_IPADDRESS_BYTES (netaddr,
250 octets[0],
251 octets[1],
252 octets[2], octets[3]);
253 sprintf (buf, "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]);
254 DBG ("_javanet_create_inetaddress(): Created ip addr string\n");
256 /* Get an InetAddress object for this IP */
257 ia_cls = (*env)->FindClass (env, "java/net/InetAddress");
258 if (ia_cls == NULL)
260 return NULL;
263 DBG ("_javanet_create_inetaddress(): Found InetAddress class\n");
265 mid = (*env)->GetStaticMethodID (env, ia_cls, "getByName",
266 "(Ljava/lang/String;)Ljava/net/InetAddress;");
267 if (mid == NULL)
269 return NULL;
272 DBG ("_javanet_create_inetaddress(): Found getByName method\n");
274 ip_str = (*env)->NewStringUTF (env, buf);
275 if (ip_str == NULL)
277 return NULL;
280 ia = (*env)->CallStaticObjectMethod (env, ia_cls, mid, ip_str);
281 if (ia == NULL)
283 return NULL;
286 DBG ("_javanet_create_inetaddress(): Called getByName method\n");
288 return ia;
289 #else /* not WITHOUT_NETWORK */
290 return NULL;
291 #endif /* not WITHOUT_NETWORK */
294 /*************************************************************************/
296 static void
297 _javanet_set_remhost_addr (JNIEnv * env, jobject this, jobject ia)
299 jclass this_cls;
300 jfieldID fid;
302 /* Set the variable in the object */
303 this_cls = (*env)->FindClass (env, "java/net/SocketImpl");
304 if (this_cls == NULL)
305 return;
307 fid =
308 (*env)->GetFieldID (env, this_cls, "address", "Ljava/net/InetAddress;");
309 if (fid == NULL)
310 return;
312 DBG ("_javanet_set_remhost_addr(): Found address field\n");
314 (*env)->SetObjectField (env, this, fid, ia);
315 DBG ("_javanet_set_remhost_addr(): Set field\n");
319 * Set's the value of the "addr" field in PlainSocketImpl with a new
320 * InetAddress for the specified addr
322 static void
323 _javanet_set_remhost (JNIEnv * env, jobject this, int netaddr)
325 jobject ia;
327 DBG ("_javanet_set_remhost(): Entered _javanet_set_remhost\n");
329 /* Get an InetAddress object */
330 ia = _javanet_create_inetaddress (env, netaddr);
331 if (ia == NULL)
332 return;
334 _javanet_set_remhost_addr (env, this, ia);
338 /*************************************************************************/
341 * Returns a 32 bit Internet address for the passed in InetAddress object
344 _javanet_get_netaddr (JNIEnv * env, jobject addr)
346 #ifndef WITHOUT_NETWORK
347 jclass cls = 0;
348 jmethodID mid;
349 jarray arr = 0;
350 jbyte *octets;
351 int netaddr, len;
353 DBG ("_javanet_get_netaddr(): Entered _javanet_get_netaddr\n");
355 if (addr == NULL)
357 JCL_ThrowException (env, "java/lang/NullPointerException",
358 "Null address");
359 return 0;
362 /* Call the getAddress method on the object to retrieve the IP address */
363 cls = (*env)->GetObjectClass (env, addr);
364 if (cls == NULL)
365 return 0;
367 mid = (*env)->GetMethodID (env, cls, "getAddress", "()[B");
368 if (mid == NULL)
369 return 0;
371 DBG ("_javanet_get_netaddr(): Got getAddress method\n");
373 arr = (*env)->CallObjectMethod (env, addr, mid);
374 if (arr == NULL)
375 return 0;
377 DBG ("_javanet_get_netaddr(): Got the address\n");
379 /* Turn the IP address into a 32 bit Internet address in network byte order */
380 len = (*env)->GetArrayLength (env, arr);
381 if (len != 4)
383 JCL_ThrowException (env, IO_EXCEPTION, "Internal Error");
384 return 0;
386 DBG ("_javanet_get_netaddr(): Length ok\n");
388 octets = (*env)->GetByteArrayElements (env, arr, 0);
389 if (octets == NULL)
390 return 0;
392 DBG ("_javanet_get_netaddr(): Grabbed bytes\n");
394 TARGET_NATIVE_NETWORK_IPADDRESS_BYTES_TO_INT (octets[0],
395 octets[1],
396 octets[2],
397 octets[3], netaddr);
399 (*env)->ReleaseByteArrayElements (env, arr, octets, 0);
400 DBG ("_javanet_get_netaddr(): Done getting addr\n");
402 return netaddr;
403 #else /* not WITHOUT_NETWORK */
404 #endif /* not WITHOUT_NETWORK */
407 /*************************************************************************/
410 * Creates a new stream or datagram socket
412 void
413 _javanet_create (JNIEnv * env, jobject this, jboolean stream)
415 #ifndef WITHOUT_NETWORK
416 int fd;
417 int result;
419 if (stream)
421 /* create a stream socket */
422 TARGET_NATIVE_NETWORK_SOCKET_OPEN_STREAM (fd, result);
423 if (result != TARGET_NATIVE_OK)
425 JCL_ThrowException (env, IO_EXCEPTION,
426 TARGET_NATIVE_LAST_ERROR_STRING ());
427 return;
430 else
432 /* create a datagram socket, set broadcast option */
433 TARGET_NATIVE_NETWORK_SOCKET_OPEN_DATAGRAM (fd, result);
434 if (result != TARGET_NATIVE_OK)
436 JCL_ThrowException (env, IO_EXCEPTION,
437 TARGET_NATIVE_LAST_ERROR_STRING ());
438 return;
440 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_BROADCAST (fd, 1, result);
441 if (result != TARGET_NATIVE_OK)
443 JCL_ThrowException (env, IO_EXCEPTION,
444 TARGET_NATIVE_LAST_ERROR_STRING ());
445 return;
449 if (stream)
450 _javanet_set_int_field (env, this, "gnu/java/net/PlainSocketImpl",
451 "native_fd", fd);
452 else
453 _javanet_set_int_field (env, this, "gnu/java/net/PlainDatagramSocketImpl",
454 "native_fd", fd);
456 if ((*env)->ExceptionOccurred (env))
458 /* Try to make sure we close the socket since close() won't work. */
461 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result);
462 if (result != TARGET_NATIVE_OK
463 && (TARGET_NATIVE_LAST_ERROR ()
464 != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL))
465 return;
467 while (result != TARGET_NATIVE_OK);
468 return;
471 #else /* not WITHOUT_NETWORK */
472 #endif /* not WITHOUT_NETWORK */
475 /*************************************************************************/
478 * Close the socket. Any underlying streams will be closed by this
479 * action as well.
481 void
482 _javanet_close (JNIEnv * env, jobject this, int stream)
484 #ifndef WITHOUT_NETWORK
485 int fd;
486 int result;
487 int error = 0;
489 fd = _javanet_get_int_field (env, this, "native_fd");
490 if (fd == -1)
491 return;
493 if (stream)
494 _javanet_set_int_field (env, this, "gnu/java/net/PlainSocketImpl",
495 "native_fd", -1);
496 else
497 _javanet_set_int_field (env, this, "gnu/java/net/PlainDatagramSocketImpl",
498 "native_fd", -1);
501 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result);
502 if (result != TARGET_NATIVE_OK)
504 /* Only throw an error when a "real" error occurs. */
505 error = TARGET_NATIVE_LAST_ERROR ();
506 if (error != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL
507 && error != ENOTCONN && error != ECONNRESET && error != EBADF)
508 JCL_ThrowException (env, IO_EXCEPTION,
509 TARGET_NATIVE_LAST_ERROR_STRING ());
512 while (error == TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL);
514 #else /* not WITHOUT_NETWORK */
515 #endif /* not WITHOUT_NETWORK */
518 /*************************************************************************/
521 * Connects to the specified destination.
523 void
524 _javanet_connect (JNIEnv * env, jobject this, jobject addr, jint port,
525 jboolean stream)
527 #ifndef WITHOUT_NETWORK
528 int netaddr, fd;
529 int result;
530 int local_address, local_port;
531 int remote_address, remote_port;
533 DBG ("_javanet_connect(): Entered _javanet_connect\n");
535 /* Pre-process input variables */
536 netaddr = _javanet_get_netaddr (env, addr);
537 if ((*env)->ExceptionOccurred (env))
538 return;
540 if (port == -1)
541 port = 0;
542 DBG ("_javanet_connect(): Got network address\n");
544 /* Grab the real socket file descriptor */
545 fd = _javanet_get_int_field (env, this, "native_fd");
546 if (fd == -1)
548 JCL_ThrowException (env, IO_EXCEPTION,
549 "Internal error: _javanet_connect(): no native file descriptor");
550 return;
552 DBG ("_javanet_connect(): Got native fd\n");
554 /* Connect up */
557 TARGET_NATIVE_NETWORK_SOCKET_CONNECT (fd, netaddr, port, result);
558 if (result != TARGET_NATIVE_OK
559 && (TARGET_NATIVE_LAST_ERROR ()
560 != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL))
562 JCL_ThrowException (env, IO_EXCEPTION,
563 TARGET_NATIVE_LAST_ERROR_STRING ());
564 return;
567 while (result != TARGET_NATIVE_OK);
569 DBG ("_javanet_connect(): Connected successfully\n");
571 /* Populate instance variables */
572 TARGET_NATIVE_NETWORK_SOCKET_GET_LOCAL_INFO (fd, local_address, local_port,
573 result);
574 if (result != TARGET_NATIVE_OK)
576 JCL_ThrowException (env, IO_EXCEPTION,
577 TARGET_NATIVE_LAST_ERROR_STRING ());
578 /* We don't care whether this succeeds. close() will cleanup later. */
579 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result);
580 return;
583 _javanet_create_localfd (env, this, stream);
584 if ((*env)->ExceptionOccurred (env))
586 /* We don't care whether this succeeds. close() will cleanup later. */
587 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result);
588 return;
590 DBG ("_javanet_connect(): Created fd\n");
592 if (stream)
593 _javanet_set_int_field (env, this, "java/net/SocketImpl", "localport",
594 local_port);
595 else
596 _javanet_set_int_field (env, this, "java/net/DatagramSocketImpl",
597 "localPort", local_port);
599 if ((*env)->ExceptionOccurred (env))
601 /* We don't care whether this succeeds. close() will cleanup later. */
602 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result);
603 return;
605 DBG ("_javanet_connect(): Set the local port\n");
607 TARGET_NATIVE_NETWORK_SOCKET_GET_REMOTE_INFO (fd, remote_address,
608 remote_port, result);
609 if (result != TARGET_NATIVE_OK)
611 JCL_ThrowException (env, IO_EXCEPTION,
612 TARGET_NATIVE_LAST_ERROR_STRING ());
613 /* We don't care whether this succeeds. close() will cleanup later. */
614 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result);
615 return;
618 if (stream)
620 if (remote_address == netaddr)
622 _javanet_set_remhost_addr (env, this, addr);
624 else
626 _javanet_set_remhost (env, this, remote_address);
628 if ((*env)->ExceptionOccurred (env))
630 /* We don't care whether this succeeds. close() will cleanup later.
632 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result);
633 return;
635 DBG ("_javanet_connect(): Set the remote host\n");
637 _javanet_set_int_field (env, this, "java/net/SocketImpl", "port",
638 remote_port);
639 if ((*env)->ExceptionOccurred (env))
641 /* We don't care whether this succeeds. close() will cleanup later.
643 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result);
644 return;
646 DBG ("_javanet_connect(): Set the remote port\n");
648 #else /* not WITHOUT_NETWORK */
649 #endif /* not WITHOUT_NETWORK */
652 /*************************************************************************/
655 * This method binds the specified address to the specified local port.
656 * Note that we have to set the local address and local
657 * port public instance variables.
659 void
660 _javanet_bind (JNIEnv * env, jobject this, jobject addr, jint port,
661 int stream)
663 #ifndef WITHOUT_NETWORK
664 jclass cls;
665 jmethodID mid;
666 jbyteArray arr = 0;
667 jbyte *octets;
668 jint fd;
669 int tmpaddr;
670 int result;
671 int local_address, local_port;
673 DBG ("_javanet_bind(): Entering native bind()\n");
675 /* Get the address to connect to */
676 cls = (*env)->GetObjectClass (env, addr);
677 if (cls == NULL)
678 return;
680 mid = (*env)->GetMethodID (env, cls, "getAddress", "()[B");
681 if (mid == NULL)
682 return;
684 DBG ("_javanet_bind(): Past getAddress method id\n");
686 arr = (*env)->CallObjectMethod (env, addr, mid);
687 if ((arr == NULL) || (*env)->ExceptionOccurred (env))
689 JCL_ThrowException (env, IO_EXCEPTION,
690 "Internal error: _javanet_bind()");
691 return;
694 DBG ("_javanet_bind(): Past call object method\n");
696 octets = (*env)->GetByteArrayElements (env, arr, 0);
697 if (octets == NULL)
698 return;
700 DBG ("_javanet_bind(): Past grab array\n");
702 /* Get the native socket file descriptor */
703 fd = _javanet_get_int_field (env, this, "native_fd");
704 if (fd == -1)
706 (*env)->ReleaseByteArrayElements (env, arr, octets, 0);
707 JCL_ThrowException (env, IO_EXCEPTION,
708 "Internal error: _javanet_bind(): no native file descriptor");
709 return;
711 DBG ("_javanet_bind(): Past native_fd lookup\n");
713 /* XXX NYI ??? */
714 _javanet_set_option (env, this, SOCKOPT_SO_REUSEADDR,
715 _javanet_create_boolean (env, JNI_TRUE));
718 /* Bind the socket */
719 TARGET_NATIVE_NETWORK_IPADDRESS_BYTES_TO_INT (octets[0],
720 octets[1],
721 octets[2],
722 octets[3], tmpaddr);
723 TARGET_NATIVE_NETWORK_SOCKET_BIND (fd, tmpaddr, port, result);
725 if (result != TARGET_NATIVE_OK)
727 char *errorstr = TARGET_NATIVE_LAST_ERROR_STRING ();
728 (*env)->ReleaseByteArrayElements (env, arr, octets, 0);
730 JCL_ThrowException (env, BIND_EXCEPTION,
731 errorstr);
732 return;
734 DBG ("_javanet_bind(): Past bind\n");
736 (*env)->ReleaseByteArrayElements (env, arr, octets, 0);
738 /* Update instance variables, specifically the local port number */
739 TARGET_NATIVE_NETWORK_SOCKET_GET_LOCAL_INFO (fd, local_address, local_port,
740 result);
741 if (result != TARGET_NATIVE_OK)
743 JCL_ThrowException (env, IO_EXCEPTION,
744 TARGET_NATIVE_LAST_ERROR_STRING ());
745 return;
748 if (stream)
749 _javanet_set_int_field (env, this, "java/net/SocketImpl",
750 "localport", local_port);
751 else
752 _javanet_set_int_field (env, this, "java/net/DatagramSocketImpl",
753 "localPort", local_port);
754 DBG ("_javanet_bind(): Past update port number\n");
756 return;
757 #else /* not WITHOUT_NETWORK */
758 #endif /* not WITHOUT_NETWORK */
761 /*************************************************************************/
764 * Starts listening on a socket with the specified number of pending
765 * connections allowed.
767 void
768 _javanet_listen (JNIEnv * env, jobject this, jint queuelen)
770 #ifndef WITHOUT_NETWORK
771 int fd;
772 int result;
774 /* Get the real file descriptor */
775 fd = _javanet_get_int_field (env, this, "native_fd");
776 if (fd == -1)
778 JCL_ThrowException (env, IO_EXCEPTION,
779 "Internal error: _javanet_listen(): no native file descriptor");
780 return;
783 /* Start listening */
784 TARGET_NATIVE_NETWORK_SOCKET_LISTEN (fd, queuelen, result);
785 if (result != TARGET_NATIVE_OK)
787 JCL_ThrowException (env, IO_EXCEPTION,
788 TARGET_NATIVE_LAST_ERROR_STRING ());
789 return;
791 #else /* not WITHOUT_NETWORK */
792 #endif /* not WITHOUT_NETWORK */
795 /*************************************************************************/
798 * Accepts a new connection and assigns it to the passed in SocketImpl
799 * object. Note that we assume this is a PlainSocketImpl just like us
801 void
802 _javanet_accept (JNIEnv * env, jobject this, jobject impl)
804 #ifndef WITHOUT_NETWORK
805 int fd, newfd;
806 int result;
807 int local_address, local_port;
808 int remote_address, remote_port;
810 /* Get the real file descriptor */
811 fd = _javanet_get_int_field (env, this, "native_fd");
812 if (fd == -1)
814 JCL_ThrowException (env, IO_EXCEPTION,
815 "Internal error: _javanet_accept(): no native file descriptor");
816 return;
819 /* Accept the connection */
822 TARGET_NATIVE_NETWORK_SOCKET_ACCEPT (fd, newfd, result);
823 if (result != TARGET_NATIVE_OK
824 && (TARGET_NATIVE_LAST_ERROR ()
825 != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL))
827 if (TARGET_NATIVE_LAST_ERROR () == EAGAIN)
828 JCL_ThrowException (env, "java/net/SocketTimeoutException",
829 "Timeout");
830 else
831 JCL_ThrowException (env, IO_EXCEPTION,
832 TARGET_NATIVE_LAST_ERROR_STRING ());
833 return;
836 while (result != TARGET_NATIVE_OK);
838 /* Populate instance variables */
839 _javanet_set_int_field (env, impl, "gnu/java/net/PlainSocketImpl",
840 "native_fd", newfd);
842 if ((*env)->ExceptionOccurred (env))
844 /* Try to make sure we close the socket since close() won't work. */
847 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result);
848 if (result != TARGET_NATIVE_OK
849 && (TARGET_NATIVE_LAST_ERROR ()
850 != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL))
851 return;
853 while (result != TARGET_NATIVE_OK);
854 return;
857 TARGET_NATIVE_NETWORK_SOCKET_GET_LOCAL_INFO (newfd, local_address,
858 local_port, result);
859 if (result != TARGET_NATIVE_OK)
861 /* We don't care whether this succeeds. close() will cleanup later. */
862 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result);
863 JCL_ThrowException (env, IO_EXCEPTION,
864 TARGET_NATIVE_LAST_ERROR_STRING ());
865 return;
868 _javanet_create_localfd (env, impl, 1);
869 if ((*env)->ExceptionOccurred (env))
871 /* We don't care whether this succeeds. close() will cleanup later. */
872 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result);
873 return;
876 _javanet_set_int_field (env, impl, "java/net/SocketImpl", "localport",
877 local_port);
878 if ((*env)->ExceptionOccurred (env))
880 /* We don't care whether this succeeds. close() will cleanup later. */
881 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result);
882 return;
885 TARGET_NATIVE_NETWORK_SOCKET_GET_REMOTE_INFO (newfd, remote_address,
886 remote_port, result);
887 if (result != TARGET_NATIVE_OK)
889 JCL_ThrowException (env, IO_EXCEPTION,
890 TARGET_NATIVE_LAST_ERROR_STRING ());
891 /* We don't care whether this succeeds. close() will cleanup later. */
892 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result);
893 return;
896 _javanet_set_remhost (env, impl, remote_address);
897 if ((*env)->ExceptionOccurred (env))
899 /* We don't care whether this succeeds. close() will cleanup later. */
900 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result);
901 return;
904 _javanet_set_int_field (env, impl, "java/net/SocketImpl", "port",
905 remote_port);
906 if ((*env)->ExceptionOccurred (env))
908 /* We don't care whether this succeeds. close() will cleanup later. */
909 TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result);
910 return;
912 #else /* not WITHOUT_NETWORK */
913 #endif /* not WITHOUT_NETWORK */
916 /*************************************************************************/
919 * Receives a buffer from a remote host. The args are:
921 * buf - The byte array into which the data received will be written
922 * offset - Offset into the byte array to start writing
923 * len - The number of bytes to read.
924 * addr - Pointer to 32 bit net address of host to receive from. If null,
925 * this parm is ignored. If pointing to an address of 0, the
926 * actual address read is stored here
927 * port - Pointer to the port to receive from. If null, this parm is ignored.
928 * If it is 0, the actual remote port received from is stored here
930 * The actual number of bytes read is returned.
933 _javanet_recvfrom (JNIEnv * env, jobject this, jarray buf, int offset,
934 int len, int *addr, int *port)
936 #ifndef WITHOUT_NETWORK
937 int fd;
938 jbyte *p;
939 int from_address, from_port;
940 int received_bytes;
942 DBG ("_javanet_recvfrom(): Entered _javanet_recvfrom\n");
944 /* Get the real file descriptor */
945 fd = _javanet_get_int_field (env, this, "native_fd");
946 if (fd == -1)
948 JCL_ThrowException (env, IO_EXCEPTION,
949 "Internal error: _javanet_recvfrom(): no native file descriptor");
950 return 0;
952 DBG ("_javanet_recvfrom(): Got native_fd\n");
954 /* Get a pointer to the buffer */
955 p = (*env)->GetByteArrayElements (env, buf, 0);
956 if (p == NULL)
957 return 0;
959 DBG ("_javanet_recvfrom(): Got buffer\n");
961 /* Read the data */
962 from_address = 0;
963 from_port = 0;
966 if (addr != NULL)
968 TARGET_NATIVE_NETWORK_SOCKET_RECEIVE_WITH_ADDRESS_PORT (fd,
969 p + offset,
970 len,
971 from_address,
972 from_port,
973 received_bytes);
975 else
977 TARGET_NATIVE_NETWORK_SOCKET_RECEIVE (fd, p + offset, len,
978 received_bytes);
981 while ((received_bytes == -1) &&
982 (TARGET_NATIVE_LAST_ERROR () ==
983 TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL));
985 if (received_bytes == -1)
987 if (TARGET_NATIVE_LAST_ERROR () == EAGAIN)
988 JCL_ThrowException (env, "java/net/SocketTimeoutException", "Timeout");
989 else
990 JCL_ThrowException (env, IO_EXCEPTION,
991 TARGET_NATIVE_LAST_ERROR_STRING ());
993 /* Cleanup and return. */
994 (*env)->ReleaseByteArrayElements (env, buf, p, 0);
995 return 0;
998 (*env)->ReleaseByteArrayElements (env, buf, p, 0);
1000 /* Handle return addr case */
1001 if (addr != NULL)
1003 (*addr) = from_address;
1004 if (port != NULL)
1005 (*port) = from_port;
1008 /* zero bytes received means recv() noticed the other side orderly
1009 closing the connection. */
1010 if (received_bytes == 0)
1011 received_bytes = -1;
1013 return (received_bytes);
1014 #else /* not WITHOUT_NETWORK */
1015 #endif /* not WITHOUT_NETWORK */
1018 /*************************************************************************/
1021 * Sends a buffer to a remote host. The args are:
1023 * buf - A byte array
1024 * offset - Index into the byte array to start sendign
1025 * len - The number of bytes to write
1026 * addr - The 32bit address to send to (may be 0)
1027 * port - The port number to send to (may be 0)
1029 void
1030 _javanet_sendto (JNIEnv * env, jobject this, jarray buf, int offset, int len,
1031 int addr, int port)
1033 #ifndef WITHOUT_NETWORK
1034 int fd;
1035 jbyte *p;
1036 int bytes_sent;
1038 /* Get the real file descriptor */
1039 fd = _javanet_get_int_field (env, this, "native_fd");
1040 if (fd == -1)
1042 JCL_ThrowException (env, IO_EXCEPTION,
1043 "Internal error: _javanet_sendto(): no native file descriptor");
1044 return;
1047 /* Get a pointer to the buffer */
1048 p = (*env)->GetByteArrayElements (env, buf, 0);
1049 if (p == NULL)
1050 return;
1052 /* We must send all the data, so repeat till done. */
1053 while (len > 0)
1055 /* Send the data */
1056 if (addr == 0)
1058 DBG ("_javanet_sendto(): Sending....\n");
1059 TARGET_NATIVE_NETWORK_SOCKET_SEND (fd, p + offset, len, bytes_sent);
1061 else
1063 DBG ("_javanet_sendto(): Sending....\n");
1064 TARGET_NATIVE_NETWORK_SOCKET_SEND_WITH_ADDRESS_PORT (fd, p + offset,
1065 len, addr, port,
1066 bytes_sent);
1069 if (bytes_sent < 0)
1071 if (TARGET_NATIVE_LAST_ERROR ()
1072 != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)
1074 JCL_ThrowException (env, IO_EXCEPTION,
1075 TARGET_NATIVE_LAST_ERROR_STRING ());
1076 break;
1079 else
1081 len -= bytes_sent;
1082 addr += bytes_sent;
1086 (*env)->ReleaseByteArrayElements (env, buf, p, 0);
1088 #else /* not WITHOUT_NETWORK */
1089 #endif /* not WITHOUT_NETWORK */
1092 /*************************************************************************/
1095 * Sets the specified option for a socket
1097 void
1098 _javanet_set_option (JNIEnv * env, jobject this, jint option_id, jobject val)
1100 #ifndef WITHOUT_NETWORK
1101 int fd;
1102 int optval;
1103 jclass cls;
1104 jmethodID mid;
1105 int address;
1106 int result;
1108 /* Get the real file descriptor */
1109 fd = _javanet_get_int_field (env, this, "native_fd");
1110 if (fd == -1)
1112 JCL_ThrowException (env, IO_EXCEPTION,
1113 "Internal error: _javanet_set_option(): no native file descriptor");
1114 return;
1117 /* We need a class object for all cases below */
1118 cls = (*env)->GetObjectClass (env, val);
1119 if (cls == NULL)
1120 return;
1122 /* Process the option request */
1123 result = TARGET_NATIVE_ERROR;
1124 switch (option_id)
1126 /* TCP_NODELAY case. val is a Boolean that tells us what to do */
1127 case SOCKOPT_TCP_NODELAY:
1128 mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z");
1129 if (mid == NULL)
1131 JCL_ThrowException (env, IO_EXCEPTION,
1132 "Internal error: _javanet_set_option()");
1133 return;
1136 /* Should be a 0 or a 1 */
1137 optval = (*env)->CallBooleanMethod (env, val, mid);
1138 if ((*env)->ExceptionOccurred (env))
1139 return;
1141 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_TCP_NODELAY (fd, optval,
1142 result);
1143 break;
1145 /* SO_LINGER case. If val is a boolean, then it will always be set
1146 to false indicating disable linger, otherwise it will be an
1147 integer that contains the linger value */
1148 case SOCKOPT_SO_LINGER:
1149 mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z");
1150 if (mid)
1152 /* We are disabling linger */
1153 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_LINGER (fd, 1, 0,
1154 result);
1156 else
1158 /* Clear exception if thrown for failure to do method lookup
1159 above */
1160 if ((*env)->ExceptionOccurred (env))
1161 (*env)->ExceptionClear (env);
1163 mid = (*env)->GetMethodID (env, cls, "intValue", "()I");
1164 if (mid == NULL)
1166 JCL_ThrowException (env, IO_EXCEPTION,
1167 "Internal error: _javanet_set_option()");
1168 return;
1171 optval = (*env)->CallIntMethod (env, val, mid);
1172 if ((*env)->ExceptionOccurred (env))
1173 return;
1175 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_LINGER (fd, 0, optval,
1176 result);
1178 break;
1180 /* SO_TIMEOUT case. Val will be an integer with the new value */
1181 /* Not writable on Linux */
1182 case SOCKOPT_SO_TIMEOUT:
1183 #ifdef SO_TIMEOUT
1184 mid = (*env)->GetMethodID (env, cls, "intValue", "()I");
1185 if (mid == NULL)
1187 JCL_ThrowException (env, IO_EXCEPTION,
1188 "Internal error: _javanet_set_option()");
1189 return;
1192 optval = (*env)->CallIntMethod (env, val, mid);
1193 if ((*env)->ExceptionOccurred (env))
1194 return;
1196 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_TIMEOUT (fd, optval, result);
1197 #else
1198 result = TARGET_NATIVE_OK;
1199 #endif
1200 break;
1202 case SOCKOPT_SO_SNDBUF:
1203 case SOCKOPT_SO_RCVBUF:
1204 mid = (*env)->GetMethodID (env, cls, "intValue", "()I");
1205 if (mid == NULL)
1207 JCL_ThrowException (env, IO_EXCEPTION,
1208 "Internal error: _javanet_set_option()");
1209 return;
1213 optval = (*env)->CallIntMethod (env, val, mid);
1214 if ((*env)->ExceptionOccurred (env))
1215 return;
1217 if (option_id == SOCKOPT_SO_SNDBUF)
1218 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_SNDBUF (fd, optval,
1219 result);
1220 else
1221 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_RCDBUF (fd, optval,
1222 result);
1223 break;
1225 /* TTL case. Val with be an Integer with the new time to live value */
1226 case SOCKOPT_IP_TTL:
1227 mid = (*env)->GetMethodID (env, cls, "intValue", "()I");
1228 if (!mid)
1230 JCL_ThrowException (env, IO_EXCEPTION,
1231 "Internal error: _javanet_set_option()");
1232 return;
1235 optval = (*env)->CallIntMethod (env, val, mid);
1236 if ((*env)->ExceptionOccurred (env))
1237 return;
1239 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_IP_TTL (fd, optval, result);
1240 break;
1242 /* Multicast Interface case - val is InetAddress object */
1243 case SOCKOPT_IP_MULTICAST_IF:
1244 address = _javanet_get_netaddr (env, val);
1246 if ((*env)->ExceptionOccurred (env))
1247 return;
1249 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_IP_MULTICAST_IF (fd, address,
1250 result);
1251 break;
1253 case SOCKOPT_SO_REUSEADDR:
1254 mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z");
1255 if (mid == NULL)
1257 JCL_ThrowException (env, IO_EXCEPTION,
1258 "Internal error: _javanet_set_option()");
1259 return;
1262 /* Should be a 0 or a 1 */
1263 optval = (*env)->CallBooleanMethod (env, val, mid);
1264 if ((*env)->ExceptionOccurred (env))
1265 return;
1267 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_REUSE_ADDRESS (fd, optval,
1268 result);
1269 break;
1271 case SOCKOPT_SO_KEEPALIVE:
1272 mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z");
1273 if (mid == NULL)
1275 JCL_ThrowException (env, IO_EXCEPTION,
1276 "Internal error: _javanet_set_option()");
1277 return;
1280 /* Should be a 0 or a 1 */
1281 optval = (*env)->CallBooleanMethod (env, val, mid);
1282 if ((*env)->ExceptionOccurred (env))
1283 return;
1285 TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_KEEP_ALIVE (fd, optval, result);
1286 break;
1288 case SOCKOPT_SO_BINDADDR:
1289 JCL_ThrowException (env, SOCKET_EXCEPTION, "This option cannot be set");
1290 break;
1292 default:
1293 JCL_ThrowException (env, SOCKET_EXCEPTION, "Unrecognized option");
1294 return;
1297 /* Check to see if above operations succeeded */
1298 if (result != TARGET_NATIVE_OK)
1300 JCL_ThrowException (env, SOCKET_EXCEPTION,
1301 TARGET_NATIVE_LAST_ERROR_STRING ());
1302 return;
1304 #else /* not WITHOUT_NETWORK */
1305 #endif /* not WITHOUT_NETWORK */
1308 /*************************************************************************/
1311 * Retrieves the specified option values for a socket
1313 jobject
1314 _javanet_get_option (JNIEnv * env, jobject this, jint option_id)
1316 #ifndef WITHOUT_NETWORK
1317 int fd;
1318 int flag, optval;
1319 int address;
1320 int result;
1322 /* Get the real file descriptor */
1323 fd = _javanet_get_int_field (env, this, "native_fd");
1324 if (fd == -1)
1326 JCL_ThrowException (env, SOCKET_EXCEPTION,
1327 "Internal error: _javanet_get_option(): no native file descriptor");
1328 return (0);
1331 /* Process the option requested */
1332 switch (option_id)
1334 /* TCP_NODELAY case. Return a Boolean indicating on or off */
1335 case SOCKOPT_TCP_NODELAY:
1336 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_TCP_NODELAY (fd, optval,
1337 result);
1338 if (result != TARGET_NATIVE_OK)
1340 JCL_ThrowException (env, SOCKET_EXCEPTION,
1341 TARGET_NATIVE_LAST_ERROR_STRING ());
1342 return (0);
1345 if (optval)
1346 return (_javanet_create_boolean (env, JNI_TRUE));
1347 else
1348 return (_javanet_create_boolean (env, JNI_FALSE));
1350 break;
1352 /* SO_LINGER case. If disabled, return a Boolean object that represents
1353 false, else return an Integer that is the value of SO_LINGER */
1354 case SOCKOPT_SO_LINGER:
1355 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_LINGER (fd, flag, optval,
1356 result);
1357 if (result != TARGET_NATIVE_OK)
1359 JCL_ThrowException (env, SOCKET_EXCEPTION,
1360 TARGET_NATIVE_LAST_ERROR_STRING ());
1361 return (0);
1364 if (optval)
1365 return (_javanet_create_integer (env, JNI_TRUE));
1366 else
1367 return (_javanet_create_boolean (env, JNI_FALSE));
1369 break;
1371 /* SO_TIMEOUT case. Return an Integer object with the timeout value */
1372 case SOCKOPT_SO_TIMEOUT:
1373 #ifdef SO_TIMEOUT
1374 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_TIMEOUT (fd, optval, result);
1375 if (result != TARGET_NATIVE_OK)
1377 JCL_ThrowException (env, SOCKET_EXCEPTION,
1378 TARGET_NATIVE_LAST_ERROR_STRING ());
1379 return (0);
1381 return (_javanet_create_integer (env, optval));
1382 #else
1383 JCL_ThrowException (env, SOCKET_EXCEPTION,
1384 "SO_TIMEOUT not supported on this platform");
1385 return (0);
1386 #endif /* not SO_TIMEOUT */
1387 break;
1389 case SOCKOPT_SO_SNDBUF:
1390 case SOCKOPT_SO_RCVBUF:
1391 if (option_id == SOCKOPT_SO_SNDBUF)
1392 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_SNDBUF (fd, optval,
1393 result);
1394 else
1395 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_RCDBUF (fd, optval,
1396 result);
1397 if (result != TARGET_NATIVE_OK)
1399 JCL_ThrowException (env, SOCKET_EXCEPTION,
1400 TARGET_NATIVE_LAST_ERROR_STRING ());
1401 return (0);
1404 return (_javanet_create_integer (env, optval));
1405 break;
1407 /* The TTL case. Return an Integer with the Time to Live value */
1408 case SOCKOPT_IP_TTL:
1409 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_IP_TTL (fd, optval, result);
1410 if (result != TARGET_NATIVE_OK)
1412 JCL_ThrowException (env, SOCKET_EXCEPTION,
1413 TARGET_NATIVE_LAST_ERROR_STRING ());
1414 return (0);
1417 return (_javanet_create_integer (env, optval));
1418 break;
1420 /* Multicast interface case */
1421 case SOCKOPT_IP_MULTICAST_IF:
1422 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_IP_MULTICAST_IF (fd, address,
1423 result);
1424 if (result != TARGET_NATIVE_OK)
1426 JCL_ThrowException (env, SOCKET_EXCEPTION,
1427 TARGET_NATIVE_LAST_ERROR_STRING ());
1428 return (0);
1431 return (_javanet_create_inetaddress (env, address));
1432 break;
1434 case SOCKOPT_SO_BINDADDR:
1435 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_BIND_ADDRESS (fd, address,
1436 result);
1437 if (result != TARGET_NATIVE_OK)
1439 JCL_ThrowException (env, SOCKET_EXCEPTION,
1440 TARGET_NATIVE_LAST_ERROR_STRING ());
1441 return (0);
1444 return (_javanet_create_inetaddress (env, address));
1445 break;
1447 case SOCKOPT_SO_REUSEADDR:
1448 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_REUSE_ADDRESS (fd, optval,
1449 result);
1450 if (result != TARGET_NATIVE_OK)
1452 JCL_ThrowException (env, SOCKET_EXCEPTION,
1453 TARGET_NATIVE_LAST_ERROR_STRING ());
1454 return (0);
1457 if (optval)
1458 return (_javanet_create_boolean (env, JNI_TRUE));
1459 else
1460 return (_javanet_create_boolean (env, JNI_FALSE));
1462 break;
1464 case SOCKOPT_SO_KEEPALIVE:
1465 TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_KEEP_ALIVE (fd, optval, result);
1466 if (result != TARGET_NATIVE_OK)
1468 JCL_ThrowException (env, SOCKET_EXCEPTION,
1469 TARGET_NATIVE_LAST_ERROR_STRING ());
1470 return (0);
1473 if (optval)
1474 return (_javanet_create_boolean (env, JNI_TRUE));
1475 else
1476 return (_javanet_create_boolean (env, JNI_FALSE));
1478 break;
1480 default:
1481 JCL_ThrowException (env, SOCKET_EXCEPTION, "No such option");
1482 return (0);
1485 return (0);
1486 #else /* not WITHOUT_NETWORK */
1487 #endif /* not WITHOUT_NETWORK */
1490 void
1491 _javanet_shutdownInput (JNIEnv * env, jobject this)
1493 int fd;
1495 /* Get the real file descriptor. */
1496 fd = _javanet_get_int_field (env, this, "native_fd");
1497 if (fd == -1)
1499 JCL_ThrowException (env, SOCKET_EXCEPTION,
1500 "Internal error: _javanet_get_option(): no native file descriptor");
1501 return;
1504 /* Shutdown input stream of socket. */
1505 if (shutdown (fd, SHUT_RD) == -1)
1507 JCL_ThrowException (env, SOCKET_EXCEPTION,
1508 TARGET_NATIVE_LAST_ERROR_STRING());
1509 return;
1513 void
1514 _javanet_shutdownOutput (JNIEnv * env, jobject this)
1516 int fd;
1518 /* Get the real file descriptor. */
1519 fd = _javanet_get_int_field (env, this, "native_fd");
1520 if (fd == -1)
1522 JCL_ThrowException (env, SOCKET_EXCEPTION,
1523 "Internal error: _javanet_get_option(): no native file descriptor");
1524 return;
1527 /* Shutdown output stream of socket. */
1528 if (shutdown (fd, SHUT_WR) == -1)
1530 JCL_ThrowException (env, SOCKET_EXCEPTION,
1531 TARGET_NATIVE_LAST_ERROR_STRING());
1532 return;
1536 /* end of file */