1 /* PlainDatagramSocketImpl.c - Native methods for PlainDatagramSocketImpl class
2    Copyright (C) 1998 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
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.
10 
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.
15 
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.
20 
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.
25 
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. */
37 
38 /* do not move; needed here because of some macro definitions */
39 #include <config.h>
40 
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
45 
46 #include <jni.h>
47 #include <jcl.h>
48 
49 #include "javanet.h"
50 
51 #include "target_native.h"
52 #ifndef WITHOUT_NETWORK
53 #include "target_native_network.h"
54 #endif /* WITHOUT_NETWORK */
55 
56 #include "gnu_java_net_PlainDatagramSocketImpl.h"
57 
58 /*
59  * Note that most of the functions in this module simply redirect to another
60  * internal function.  Why?  Because many of these functions are shared
61  * with PlainSocketImpl.
62  */
63 
64 /*************************************************************************/
65 
66 /*
67  * Creates a new datagram socket
68  */
69 JNIEXPORT void JNICALL
Java_gnu_java_net_PlainDatagramSocketImpl_create(JNIEnv * env,jobject obj)70 Java_gnu_java_net_PlainDatagramSocketImpl_create (JNIEnv * env, jobject obj)
71 {
72   assert (env != NULL);
73   assert ((*env) != NULL);
74 
75 #ifndef WITHOUT_NETWORK
76   _javanet_create (env, obj, 0);
77 #else /* not WITHOUT_NETWORK */
78 #endif /* not WITHOUT_NETWORK */
79 }
80 
81 /*************************************************************************/
82 
83 /*
84  * Close the socket.
85  */
86 JNIEXPORT void JNICALL
Java_gnu_java_net_PlainDatagramSocketImpl_close(JNIEnv * env,jobject obj)87 Java_gnu_java_net_PlainDatagramSocketImpl_close (JNIEnv * env, jobject obj)
88 {
89   assert (env != NULL);
90   assert ((*env) != NULL);
91 
92 #ifndef WITHOUT_NETWORK
93   _javanet_close (env, obj, 0);
94 #else /* not WITHOUT_NETWORK */
95 #endif /* not WITHOUT_NETWORK */
96 }
97 
98 /*************************************************************************/
99 
100 /*
101  * This method binds the specified address to the specified local port.
102  * Note that we have to set the local address and local port public instance
103  * variables.
104  */
105 JNIEXPORT void JNICALL
Java_gnu_java_net_PlainDatagramSocketImpl_bind(JNIEnv * env,jobject obj,jint port,jobject addr)106 Java_gnu_java_net_PlainDatagramSocketImpl_bind (JNIEnv * env, jobject obj,
107 						jint port, jobject addr)
108 {
109   assert (env != NULL);
110   assert ((*env) != NULL);
111 
112 #ifndef WITHOUT_NETWORK
113   _javanet_bind (env, obj, addr, port, 0);
114 #else /* not WITHOUT_NETWORK */
115 #endif /* not WITHOUT_NETWORK */
116 }
117 
118 /*************************************************************************/
119 
120 /*
121  * This method sets the specified option for a socket
122  */
123 JNIEXPORT void JNICALL
Java_gnu_java_net_PlainDatagramSocketImpl_setOption(JNIEnv * env,jobject obj,jint option_id,jobject val)124 Java_gnu_java_net_PlainDatagramSocketImpl_setOption (JNIEnv * env,
125 						     jobject obj,
126 						     jint option_id,
127 						     jobject val)
128 {
129   assert (env != NULL);
130   assert ((*env) != NULL);
131 
132 #ifndef WITHOUT_NETWORK
133   _javanet_set_option (env, obj, option_id, val);
134 #else /* not WITHOUT_NETWORK */
135 #endif /* not WITHOUT_NETWORK */
136 }
137 
138 /*************************************************************************/
139 
140 /*
141  * This method sets the specified option for a socket
142  */
143 JNIEXPORT jobject JNICALL
Java_gnu_java_net_PlainDatagramSocketImpl_getOption(JNIEnv * env,jobject obj,jint option_id)144 Java_gnu_java_net_PlainDatagramSocketImpl_getOption (JNIEnv * env,
145 						     jobject obj,
146 						     jint option_id)
147 {
148   assert (env != NULL);
149   assert ((*env) != NULL);
150 
151 #ifndef WITHOUT_NETWORK
152   return (_javanet_get_option (env, obj, option_id));
153 #else /* not WITHOUT_NETWORK */
154   return NULL;
155 #endif /* not WITHOUT_NETWORK */
156 }
157 
158 /*************************************************************************/
159 
160 /*
161  * Reads a buffer from a remote host
162  */
163 JNIEXPORT void JNICALL
Java_gnu_java_net_PlainDatagramSocketImpl_receive0(JNIEnv * env,jobject obj,jobject packet)164 Java_gnu_java_net_PlainDatagramSocketImpl_receive0 (JNIEnv * env, jobject obj,
165 						    jobject packet)
166 {
167 #ifndef WITHOUT_NETWORK
168   int addr, port, bytes_read;
169   unsigned int maxlen, offset;
170   jclass cls, addr_cls;
171   jfieldID fid;
172   jmethodID mid;
173   jarray arr;
174   unsigned char octets[4];
175   char ip_str[16];
176   jobject ip_str_obj, addr_obj;
177 
178   assert (env != NULL);
179   assert ((*env) != NULL);
180 
181   addr = 0;
182   port = 0;
183   maxlen = 0;
184   offset = 0;
185   bytes_read = 0;
186 
187   if (packet == NULL)
188     {
189       JCL_ThrowException (env, "java/lang/NullPointerException",
190 			  "Null datagram packet");
191       return;
192     }
193 
194   /* Get the buffer from the packet */
195   cls = (*env)->GetObjectClass (env, packet);
196   if (cls == NULL)
197     {
198       JCL_ThrowException (env, IO_EXCEPTION, "Internal error");
199       return;
200     }
201 
202   mid = (*env)->GetMethodID (env, cls, "getData", "()[B");
203   if (mid == NULL)
204     {
205       JCL_ThrowException (env, IO_EXCEPTION, "Internal error: getData");
206       return;
207     }
208 
209   arr = (*env)->CallObjectMethod (env, packet, mid);
210   if ((*env)->ExceptionOccurred (env))
211     return;
212   if (arr == NULL)
213     {
214       JCL_ThrowException (env, IO_EXCEPTION, "Internal error: call getData");
215       return;
216     }
217 
218   /* Now get the offset from the packet */
219   mid = (*env)->GetMethodID (env, cls, "getOffset", "()I");
220   if (mid == NULL)
221     {
222       JCL_ThrowException (env, IO_EXCEPTION, "Internal error: getOffset");
223       return;
224     }
225 
226   offset = (*env)->CallIntMethod (env, packet, mid);
227   if ((*env)->ExceptionOccurred (env))
228     return;
229 
230   DBG ("PlainDatagramSocketImpl.receive(): Got the offset\n");
231 
232   /* Now get the maximal available length from the packet */
233   fid = (*env)->GetFieldID (env, cls, "maxlen", "I");
234   if (fid == NULL)
235     {
236       JCL_ThrowException (env, IO_EXCEPTION, "Internal error: maxlen");
237       return;
238     }
239 
240   maxlen = (*env)->GetIntField (env, packet, fid);
241   if ((*env)->ExceptionOccurred (env))
242     return;
243 
244   /* Receive the packet */
245   /* should we try some sort of validation on the length? */
246   bytes_read =
247     _javanet_recvfrom (env, obj, arr, offset, maxlen, &addr, &port);
248   if ((*env)->ExceptionOccurred (env))
249     return;
250   if (bytes_read == -1)
251     {
252       JCL_ThrowException (env, IO_EXCEPTION, "Internal error: receive");
253       return;
254     }
255 
256   DBG ("PlainDatagramSocketImpl.receive(): Received packet\n");
257 
258   /* Store the address */
259   TARGET_NATIVE_NETWORK_INT_TO_IPADDRESS_BYTES (addr,
260 						octets[0],
261 						octets[1],
262 						octets[2], octets[3]);
263   sprintf (ip_str, "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]);
264   ip_str_obj = (*env)->NewStringUTF (env, ip_str);
265   if (ip_str_obj == NULL)
266     {
267       JCL_ThrowException (env, IO_EXCEPTION, "Internal error: new string");
268       return;
269     }
270 
271   addr_cls = (*env)->FindClass (env, "java/net/InetAddress");
272   if (addr_cls == NULL)
273     {
274       JCL_ThrowException (env, IO_EXCEPTION,
275 			  "Internal error: InetAddress class");
276       return;
277     }
278   DBG ("PlainDatagramSocketImpl.receive(): Found InetAddress class\n");
279 
280   mid = (*env)->GetStaticMethodID (env, addr_cls, "getByName",
281 				   "(Ljava/lang/String;)Ljava/net/InetAddress;");
282   if (mid == NULL)
283     {
284       JCL_ThrowException (env, IO_EXCEPTION, "Internal Error");
285       return;
286     }
287   DBG
288     ("PlainDatagramSocketImpl.receive(): Found InetAddress.getByName method\n");
289 
290   addr_obj = (*env)->CallStaticObjectMethod (env, addr_cls, mid, ip_str_obj);
291   if ((*env)->ExceptionOccurred (env))
292     return;
293 
294   mid = (*env)->GetMethodID (env, cls, "setAddress",
295 			     "(Ljava/net/InetAddress;)V");
296   if (mid == NULL)
297     {
298       JCL_ThrowException (env, IO_EXCEPTION, "Internal error: setAddress");
299       return;
300     }
301 
302   (*env)->CallVoidMethod (env, packet, mid, addr_obj);
303   if ((*env)->ExceptionOccurred (env))
304     return;
305 
306   DBG ("PlainDatagramSocketImpl.receive(): Stored the address\n");
307 
308   /* Store the port */
309   mid = (*env)->GetMethodID (env, cls, "setPort", "(I)V");
310   if (mid == NULL)
311     {
312       JCL_ThrowException (env, IO_EXCEPTION, "Internal error: setPort");
313       return;
314     }
315 
316   (*env)->CallVoidMethod (env, packet, mid, port);
317   if ((*env)->ExceptionOccurred (env))
318     return;
319 
320   DBG ("PlainDatagramSocketImpl.receive(): Stored the port\n");
321 
322   /* Store back the length */
323   fid = (*env)->GetFieldID (env, cls, "length", "I");
324   if (fid == NULL)
325     {
326       JCL_ThrowException (env, IO_EXCEPTION, "Internal error: length");
327       return;
328     }
329 
330   (*env)->SetIntField (env, packet, fid, bytes_read);
331   if ((*env)->ExceptionOccurred (env))
332     return;
333 
334   DBG ("PlainDatagramSocketImpl.receive(): Stored the length\n");
335 #else /* not WITHOUT_NETWORK */
336 #endif /* not WITHOUT_NETWORK */
337 }
338 
339 /*************************************************************************/
340 
341 /*
342  * Writes a buffer to the remote host
343  */
344 JNIEXPORT void JNICALL
Java_gnu_java_net_PlainDatagramSocketImpl_sendto(JNIEnv * env,jobject obj,jobject addr,jint port,jarray buf,jint offset,jint len)345 Java_gnu_java_net_PlainDatagramSocketImpl_sendto (JNIEnv * env, jobject obj,
346 						  jobject addr, jint port,
347 						  jarray buf, jint offset,
348 						  jint len)
349 {
350 #ifndef WITHOUT_NETWORK
351   jint netAddress;
352 
353   assert (env != NULL);
354   assert ((*env) != NULL);
355 
356   netAddress = _javanet_get_netaddr (env, addr);
357   if ((*env)->ExceptionOccurred (env))
358     return;
359 
360   DBG ("PlainDatagramSocketImpl.sendto(): have addr\n");
361 
362   _javanet_sendto (env, obj, buf, offset, len, netAddress, port);
363   if ((*env)->ExceptionOccurred (env))
364     return;
365 
366   DBG ("PlainDatagramSocketImpl.sendto(): finished\n");
367 #else /* not WITHOUT_NETWORK */
368 #endif /* not WITHOUT_NETWORK */
369 }
370 
371 /*************************************************************************/
372 
373 /*
374  * Joins a multicast group
375  */
376 JNIEXPORT void JNICALL
Java_gnu_java_net_PlainDatagramSocketImpl_join(JNIEnv * env,jobject obj,jobject addr)377 Java_gnu_java_net_PlainDatagramSocketImpl_join (JNIEnv * env, jobject obj,
378 						jobject addr)
379 {
380 #ifndef WITHOUT_NETWORK
381   jint netAddress;
382   int fd;
383   int result;
384 
385   assert (env != NULL);
386   assert ((*env) != NULL);
387 
388   netAddress = _javanet_get_netaddr (env, addr);
389   if ((*env)->ExceptionOccurred (env))
390     return;
391 
392   fd = _javanet_get_int_field (env, obj, "native_fd");
393   if ((*env)->ExceptionOccurred (env))
394     return;
395 
396   DBG ("PlainDatagramSocketImpl.join(): have native fd\n");
397 
398   TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_ADD_MEMBERSHIP (fd, netAddress,
399 							  result);
400 
401   if (result != TARGET_NATIVE_OK)
402     {
403       JCL_ThrowException (env, IO_EXCEPTION,
404 			  TARGET_NATIVE_LAST_ERROR_STRING ());
405       return;
406     }
407 
408   DBG ("PlainDatagramSocketImpl.join(): finished\n");
409 #else /* not WITHOUT_NETWORK */
410 #endif /* not WITHOUT_NETWORK */
411 }
412 
413 /*************************************************************************/
414 
415 /*
416  * Leaves a multicast group
417  */
418 JNIEXPORT void JNICALL
Java_gnu_java_net_PlainDatagramSocketImpl_leave(JNIEnv * env,jobject obj,jobject addr)419 Java_gnu_java_net_PlainDatagramSocketImpl_leave (JNIEnv * env, jobject obj,
420 						 jobject addr)
421 {
422 #ifndef WITHOUT_NETWORK
423   jint netAddress;
424   int fd;
425   int result;
426 
427   assert (env != NULL);
428   assert ((*env) != NULL);
429 
430   netAddress = _javanet_get_netaddr (env, addr);
431   if ((*env)->ExceptionOccurred (env))
432     return;
433 
434   fd = _javanet_get_int_field (env, obj, "native_fd");
435   if ((*env)->ExceptionOccurred (env))
436     return;
437 
438   DBG ("PlainDatagramSocketImpl.leave(): have native fd\n");
439 
440   TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_DROP_MEMBERSHIP (fd, netAddress,
441 							   result);
442   if (result != TARGET_NATIVE_OK)
443     {
444       JCL_ThrowException (env, IO_EXCEPTION,
445 			  TARGET_NATIVE_LAST_ERROR_STRING ());
446       return;
447     }
448 
449   DBG ("PlainDatagramSocketImpl.leave(): finished\n");
450 #else /* not WITHOUT_NETWORK */
451 #endif /* not WITHOUT_NETWORK */
452 }
453