blob: dca30316a15b8407cf422e6bcfa6716f84734768 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2003 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25#include <string.h>
26#include <stdlib.h>
27#include <stddef.h>
28#include <jni.h>
29#include "SharedMemory.h"
30#include "com_sun_tools_jdi_SharedMemoryConnection.h"
31#include "jdwpTransport.h"
32#include "shmemBase.h"
33#include "sys.h"
34
35/*
36 * JNI interface to the shared memory transport. These JNI methods
37 * call the base shared memory support to do the real work.
38 *
39 * That is, this is the front-ends interface to our shared memory
40 * communication code.
41 */
42
43/*
44 * Cached architecture
45 */
46static int byte_ordering_known;
47static int is_big_endian;
48
49
50/*
51 * Returns 1 if big endian architecture
52 */
53static int isBigEndian() {
54 if (!byte_ordering_known) {
55 unsigned int i = 0xff000000;
56 if (((char *)(&i))[0] != 0) {
57 is_big_endian = 1;
58 } else {
59 is_big_endian = 0;
60 }
61 byte_ordering_known = 1;
62 }
63 return is_big_endian;
64}
65
66/*
67 * Convert to big endian
68 */
69static jint intToBigInt(jint i) {
70 unsigned int b[4];
71 if (isBigEndian()) {
72 return i;
73 }
74 b[0] = (i >> 24) & 0xff;
75 b[1] = (i >> 16) & 0xff;
76 b[2] = (i >> 8) & 0xff;
77 b[3] = i & 0xff;
78
79 /*
80 * It doesn't matter that jint is signed as we are or'ing
81 * and hence end up with the correct bits.
82 */
83 return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
84}
85
86/*
87 * Convert unsigned short to big endian
88 */
89static unsigned short shortToBigShort(unsigned short s) {
90 unsigned int b[2];
91 if (isBigEndian()) {
92 return s;
93 }
94 b[0] = (s >> 8) & 0xff;
95 b[1] = s & 0xff;
96 return (b[1] << 8) + b[0];
97}
98
99/*
100 * Create a byte[] from a packet struct. All data in the byte array
101 * is JDWP packet suitable for wire transmission. That is, all fields,
102 * and data are in big-endian format as required by the JDWP
103 * specification.
104 */
105static jbyteArray
106packetToByteArray(JNIEnv *env, jdwpPacket *str)
107{
108 jbyteArray array;
109 jsize data_length;
110 jint total_length;
111 jint tmpInt;
112
113 total_length = str->type.cmd.len;
114 data_length = total_length - 11;
115
116 /* total packet length is header + data */
117 array = (*env)->NewByteArray(env, total_length);
118 if ((*env)->ExceptionOccurred(env)) {
119 return NULL;
120 }
121
122 /* First 4 bytes of packet are the length (in big endian format) */
123 tmpInt = intToBigInt((unsigned int)total_length);
124 (*env)->SetByteArrayRegion(env, array, 0, 4, (const jbyte *)&tmpInt);
125
126 /* Next 4 bytes are the id field */
127 tmpInt = intToBigInt(str->type.cmd.id);
128 (*env)->SetByteArrayRegion(env, array, 4, 4, (const jbyte *)&tmpInt);
129
130 /* next byte is the flags */
131 (*env)->SetByteArrayRegion(env, array, 8, 1, (const jbyte *)&(str->type.cmd.flags));
132
133 /* next two bytes are either the error code or the command set/command */
134 if (str->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
135 short s = shortToBigShort(str->type.reply.errorCode);
136 (*env)->SetByteArrayRegion(env, array, 9, 2, (const jbyte *)&(s));
137 } else {
138 (*env)->SetByteArrayRegion(env, array, 9, 1, (const jbyte *)&(str->type.cmd.cmdSet));
139 (*env)->SetByteArrayRegion(env, array, 10, 1, (const jbyte *)&(str->type.cmd.cmd));
140 }
141
142 /* finally the data */
143
144 if (data_length > 0) {
145 (*env)->SetByteArrayRegion(env, array, 11,
146 data_length, str->type.cmd.data);
147 if ((*env)->ExceptionOccurred(env)) {
148 return NULL;
149 }
150 }
151
152 return array;
153}
154
155/*
156 * Fill a packet struct from a byte array. The byte array is a
157 * JDWP packet suitable for wire transmission. That is, all fields,
158 * and data are in big-endian format as required by the JDWP
159 * specification. We thus need to convert the fields from big
160 * endian to the platform endian.
161 *
162 * The jbyteArray provided to this function is assumed to
163 * of a length than is equal or greater than the length of
164 * the JDWP packet that is contains.
165 */
166static void
167byteArrayToPacket(JNIEnv *env, jbyteArray b, jdwpPacket *str)
168{
169 jsize total_length, data_length;
170 jbyte *data;
171 unsigned char pktHeader[11]; /* sizeof length + id + flags + cmdSet + cmd */
172
173 /*
174 * Get the packet header
175 */
176 (*env)->GetByteArrayRegion(env, b, 0, sizeof(pktHeader), pktHeader);
177
178 total_length = (int)pktHeader[3] | ((int)pktHeader[2] << 8) |
179 ((int)pktHeader[1] << 16) | ((int)pktHeader[0] << 24);
180 /*
181 * The id field is in big endian (also errorCode field in the case
182 * of reply packets).
183 */
184 str->type.cmd.id = (int)pktHeader[7] | ((int)pktHeader[6] << 8) |
185 ((int)pktHeader[5] << 16) | ((int)pktHeader[4] << 24);
186
187 str->type.cmd.flags = (jbyte)pktHeader[8];
188
189 if (str->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
190 str->type.reply.errorCode = (int)pktHeader[9] + ((int)pktHeader[10] << 8);
191 } else {
192 /* command packet */
193 str->type.cmd.cmdSet = (jbyte)pktHeader[9];
194 str->type.cmd.cmd = (jbyte)pktHeader[10];
195 }
196
197 /*
198 * The length of the JDWP packet is 11 + data
199 */
200 data_length = total_length - 11;
201
202 if (data_length == 0) {
203 data = NULL;
204 } else {
205 data = malloc(data_length);
206 if (data == NULL) {
207 throwException(env, "java/lang/OutOfMemoryError",
208 "Unable to allocate command data buffer");
209 return;
210 }
211
212 (*env)->GetByteArrayRegion(env, b, 11, /*sizeof(CmdPacket)+4*/ data_length, data);
213 if ((*env)->ExceptionOccurred(env)) {
214 free(data);
215 return;
216 }
217 }
218
219 str->type.cmd.len = total_length;
220 str->type.cmd.data = data;
221}
222
223static void
224freePacketData(jdwpPacket *packet)
225{
226 if (packet->type.cmd.len > 0) {
227 free(packet->type.cmd.data);
228 }
229}
230
231/*
232 * Class: com_sun_tools_jdi_SharedMemoryConnection
233 * Method: close0
234 * Signature: (J)V
235 */
236JNIEXPORT void JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_close0
237 (JNIEnv *env, jobject thisObject, jlong id)
238{
239 SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
240 shmemBase_closeConnection(connection);
241}
242
243/*
244 * Class: com_sun_tools_jdi_SharedMemoryConnection
245 * Method: receiveByte0
246 * Signature: (J)B
247 */
248JNIEXPORT jbyte JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_receiveByte0
249 (JNIEnv *env, jobject thisObject, jlong id)
250{
251 SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
252 jbyte b = 0;
253 jint rc;
254
255 rc = shmemBase_receiveByte(connection, &b);
256 if (rc != SYS_OK) {
257 throwShmemException(env, "shmemBase_receiveByte failed", rc);
258 }
259
260 return b;
261}
262
263/*
264 * Class: com_sun_tools_jdi_SharedMemoryConnection
265 * Method: receivePacket0
266 * Signature: (JLcom/sun/tools/jdi/Packet;)V
267 */
268JNIEXPORT jbyteArray JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_receivePacket0
269 (JNIEnv *env, jobject thisObject, jlong id)
270{
271 SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
272 jdwpPacket packet;
273 jint rc;
274
275 rc = shmemBase_receivePacket(connection, &packet);
276 if (rc != SYS_OK) {
277 throwShmemException(env, "shmemBase_receivePacket failed", rc);
278 return NULL;
279 } else {
280 jbyteArray array = packetToByteArray(env, &packet);
281
282 /* Free the packet even if there was an exception above */
283 freePacketData(&packet);
284 return array;
285 }
286}
287
288/*
289 * Class: com_sun_tools_jdi_SharedMemoryConnection
290 * Method: sendByte0
291 * Signature: (JB)V
292 */
293JNIEXPORT void JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_sendByte0
294 (JNIEnv *env, jobject thisObject, jlong id, jbyte b)
295{
296 SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
297 jint rc;
298
299 rc = shmemBase_sendByte(connection, b);
300 if (rc != SYS_OK) {
301 throwShmemException(env, "shmemBase_sendByte failed", rc);
302 }
303}
304
305/*
306 * Class: com_sun_tools_jdi_SharedMemoryConnection
307 * Method: sendPacket0
308 * Signature: (JLcom/sun/tools/jdi/Packet;)V
309 */
310JNIEXPORT void JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_sendPacket0
311 (JNIEnv *env, jobject thisObject, jlong id, jbyteArray b)
312{
313 SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
314 jdwpPacket packet;
315 jint rc;
316
317 byteArrayToPacket(env, b, &packet);
318 if ((*env)->ExceptionOccurred(env)) {
319 return;
320 }
321
322 rc = shmemBase_sendPacket(connection, &packet);
323 if (rc != SYS_OK) {
324 throwShmemException(env, "shmemBase_sendPacket failed", rc);
325 }
326 freePacketData(&packet);
327}