001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.cldc.io.j2me.socket;
028:
029: import java.io.*;
030: import javax.microedition.io.*;
031: import com.sun.cldc.io.*;
032:
033: /**
034: * Connection to the J2ME socket API.
035: *
036: * @version 1.0 1/16/2000
037: */
038:
039: public class Protocol implements ConnectionBaseInterface,
040: StreamConnection {
041:
042: /** Socket object used by native code */
043: int handle;
044:
045: /** Access mode */
046: private int mode;
047:
048: /** Open count */
049: int opens = 0;
050:
051: /** Connection open flag */
052: private boolean copen = false;
053:
054: /** Input stream open flag */
055: protected boolean isopen = false;
056:
057: /** Output stream open flag */
058: protected boolean osopen = false;
059:
060: /**
061: * Open the connection
062: */
063: public void open(String name, int mode, boolean timeouts)
064: throws IOException {
065: throw new RuntimeException(
066: /* #ifdef VERBOSE_EXCEPTIONS */
067: /// skipped "Should not be called"
068: /* #endif */
069: );
070: }
071:
072: /**
073: * Open the connection
074: * @param name the target for the connection. It must be in this
075: * format: "//<name or IP number>:<port number>"
076: * @param mode read/write mode of the connection (currently ignored).
077: * @param timeouts A flag to indicate that the called wants timeout
078: * exceptions (currently ignored).
079: */
080: public Connection openPrim(String name, int mode, boolean timeouts)
081: throws IOException {
082: if (!name.startsWith("//")) {
083: throw new IOException(
084: /* #ifdef VERBOSE_EXCEPTIONS */
085: /// skipped "bad socket connection name: " + name
086: /* #endif */
087: );
088: }
089: int i = name.indexOf(':');
090: if (i < 0) {
091: throw new IOException(
092: /* #ifdef VERBOSE_EXCEPTIONS */
093: /// skipped "bad socket connection name: port missing"
094: /* #endif */
095: );
096: }
097: String hostname = name.substring(2, i);
098: int port;
099: try {
100: port = Integer.parseInt(name.substring(i + 1));
101: } catch (NumberFormatException e) {
102: throw new IOException(
103: /* #ifdef VERBOSE_EXCEPTIONS */
104: /// skipped "bad socket connection name: bad port"
105: /* #endif */
106: );
107: }
108: // cstring is always NUL terminated (note the extra byte allocated).
109: // This avoids awkward char array manipulation in C code.
110: byte cstring[] = new byte[hostname.length() + 1];
111: for (int n = 0; n < hostname.length(); n++) {
112: cstring[n] = (byte) (hostname.charAt(n));
113: }
114: if ((this .handle = open0(cstring, port, mode)) < 0) {
115: int errorCode = this .handle & 0x7fffffff;
116: throw new IOException(
117: /* #ifdef VERBOSE_EXCEPTIONS */
118: /// skipped "connection failed: error = " + errorCode
119: /* #endif */
120: );
121: }
122: opens++;
123: copen = true;
124: this .mode = mode;
125: return this ;
126: }
127:
128: /**
129: * Open the connection
130: * @param handle an already formed socket handle
131: * <p>
132: * This function is only used by com.sun.cldc.io.j2me.socketserver;
133: */
134: public void open(int handle, int mode) throws IOException {
135: this .handle = handle;
136: opens++;
137: copen = true;
138: this .mode = mode;
139: }
140:
141: /**
142: * Ensure connection is open
143: */
144: void ensureOpen() throws IOException {
145: if (!copen) {
146: throw new IOException(
147: /* #ifdef VERBOSE_EXCEPTIONS */
148: /// skipped "Connection closed"
149: /* #endif */
150: );
151: }
152: }
153:
154: /**
155: * Returns an input stream for this socket.
156: *
157: * @return an input stream for reading bytes from this socket.
158: * @exception IOException if an I/O error occurs when creating the
159: * input stream.
160: */
161: synchronized public InputStream openInputStream()
162: throws IOException {
163: ensureOpen();
164: if ((mode & Connector.READ) == 0) {
165: throw new IOException(
166: /* #ifdef VERBOSE_EXCEPTIONS */
167: /// skipped "Connection not open for reading"
168: /* #endif */
169: );
170: }
171: if (isopen) {
172: throw new IOException(
173: /* #ifdef VERBOSE_EXCEPTIONS */
174: /// skipped "Input stream already opened"
175: /* #endif */
176: );
177: }
178: isopen = true;
179: InputStream in = new PrivateInputStream(this );
180: opens++;
181: return in;
182: }
183:
184: /**
185: * Returns an output stream for this socket.
186: *
187: * @return an output stream for writing bytes to this socket.
188: * @exception IOException if an I/O error occurs when creating the
189: * output stream.
190: */
191: synchronized public OutputStream openOutputStream()
192: throws IOException {
193: ensureOpen();
194: if ((mode & Connector.WRITE) == 0) {
195: throw new IOException(
196: /* #ifdef VERBOSE_EXCEPTIONS */
197: /// skipped "Connection not open for writing"
198: /* #endif */
199: );
200: }
201: if (osopen) {
202: throw new IOException(
203: /* #ifdef VERBOSE_EXCEPTIONS */
204: /// skipped "Output stream already opened"
205: /* #endif */
206: );
207: }
208: osopen = true;
209: OutputStream os = new PrivateOutputStream(this );
210: opens++;
211: return os;
212: }
213:
214: /**
215: * Close the connection.
216: *
217: * @exception IOException if an I/O error occurs when closing the
218: * connection.
219: */
220: synchronized public void close() throws IOException {
221: if (copen) {
222: copen = false;
223: realClose();
224: }
225: }
226:
227: /**
228: * Close the connection.
229: *
230: * @exception IOException if an I/O error occurs.
231: */
232: synchronized void realClose() throws IOException {
233: if (--opens == 0) {
234: close0(this .handle);
235: }
236: }
237:
238: /**
239: * Open and return a data input stream for a connection.
240: *
241: * @return An input stream
242: * @exception IOException If an I/O error occurs
243: */
244: public DataInputStream openDataInputStream() throws IOException {
245: return new DataInputStream(openInputStream());
246: }
247:
248: /**
249: * Open and return a data output stream for a connection.
250: *
251: * @return An input stream
252: * @exception IOException If an I/O error occurs
253: */
254: public DataOutputStream openDataOutputStream() throws IOException {
255: return new DataOutputStream(openOutputStream());
256: }
257:
258: /*
259: * A note about readByte()
260: *
261: * This function will return an unsigned byte, or -1.
262: * -1 means that EOF was reached.
263: */
264:
265: protected static native int open0(byte hostname[], int port,
266: int mode);
267:
268: protected static native int readBuf(int handle, byte b[], int off,
269: int len);
270:
271: protected static native int readByte(int handle);
272:
273: protected static native int writeBuf(int handle, byte b[], int off,
274: int len);
275:
276: protected static native int writeByte(int handle, int b);
277:
278: protected static native int available0(int handle);
279:
280: protected static native void close0(int handle);
281: }
282:
283: /**
284: * Input stream for the connection
285: */
286: class PrivateInputStream extends InputStream {
287:
288: /**
289: * Pointer to the connection
290: */
291: private Protocol parent;
292:
293: /**
294: * End of file flag
295: */
296: boolean eof = false;
297:
298: /**
299: * Constructor
300: * @param pointer to the connection object
301: *
302: * @exception IOException if an I/O error occurs.
303: */
304: /* public */PrivateInputStream(Protocol parent) throws IOException {
305: this .parent = parent;
306: }
307:
308: /**
309: * Check the stream is open
310: *
311: * @exception IOException if it is not.
312: */
313: void ensureOpen() throws IOException {
314: if (parent == null) {
315: throw new IOException(
316: /* #ifdef VERBOSE_EXCEPTIONS */
317: /// skipped "Stream closed"
318: /* #endif */
319: );
320: }
321: }
322:
323: /**
324: * Reads the next byte of data from the input stream.
325: * <p>
326: * Polling the native code is done here to allow for simple
327: * asynchronous native code to be written. Not all implementations
328: * work this way (they block in the native code) but the same
329: * Java code works for both.
330: *
331: * @return the next byte of data, or <code>-1</code> if the end of the
332: * stream is reached.
333: * @exception IOException if an I/O error occurs.
334: */
335: synchronized public int read() throws IOException {
336: int res;
337: ensureOpen();
338: if (eof) {
339: return -1;
340: }
341: res = Protocol.readByte(parent.handle);
342: if (res == -1) {
343: eof = true;
344: }
345: if (parent == null) {
346: throw new InterruptedIOException();
347: }
348: return res;
349: }
350:
351: /**
352: * Reads up to <code>len</code> bytes of data from the input stream into
353: * an array of bytes.
354: * <p>
355: * Polling the native code is done here to allow for simple
356: * asynchronous native code to be written. Not all implementations
357: * work this way (they block in the native code) but the same
358: * Java code works for both.
359: *
360: * @param b the buffer into which the data is read.
361: * @param off the start offset in array <code>b</code>
362: * at which the data is written.
363: * @param len the maximum number of bytes to read.
364: * @return the total number of bytes read into the buffer, or
365: * <code>-1</code> if there is no more data because the end of
366: * the stream has been reached.
367: * @exception IOException if an I/O error occurs.
368: */
369: synchronized public int read(byte b[], int off, int len)
370: throws IOException {
371: ensureOpen();
372: if (eof) {
373: return -1;
374: }
375: if (len == 0) {
376: return 0;
377: }
378: // Check for array index out of bounds, and NullPointerException,
379: // so that the native code doesn't need to do it
380: int test = b[off] + b[off + len - 1];
381:
382: int n = 0;
383: while (n < len) {
384: int count = Protocol.readBuf(parent.handle, b, off + n, len
385: - n);
386: if (count == -1) {
387: eof = true;
388: if (n == 0) {
389: n = -1;
390: }
391: break;
392: }
393: n += count;
394: if (n == len) {
395: break;
396: }
397: }
398: if (parent == null) {
399: throw new InterruptedIOException();
400: }
401: return n;
402: }
403:
404: /**
405: * Returns the number of bytes that can be read (or skipped over) from
406: * this input stream without blocking by the next caller of a method for
407: * this input stream.
408: *
409: * @return the number of bytes that can be read from this input stream.
410: * @exception IOException if an I/O error occurs.
411: */
412: synchronized public int available() throws IOException {
413: ensureOpen();
414: return Protocol.available0(parent.handle);
415: }
416:
417: /**
418: * Close the stream.
419: *
420: * @exception IOException if an I/O error occurs
421: */
422: public void close() throws IOException {
423: if (parent != null) {
424: ensureOpen();
425: parent.realClose();
426: parent.isopen = false;
427: parent = null;
428: }
429: }
430: }
431:
432: /**
433: * Output stream for the connection
434: */
435: class PrivateOutputStream extends OutputStream {
436:
437: /**
438: * Pointer to the connection
439: */
440: private Protocol parent;
441:
442: /**
443: * Constructor
444: * @param pointer to the connection object
445: *
446: * @exception IOException if an I/O error occurs.
447: */
448: /* public */PrivateOutputStream(Protocol parent)
449: throws IOException {
450: this .parent = parent;
451: }
452:
453: /**
454: * Check the stream is open
455: *
456: * @exception IOException if it is not.
457: */
458: void ensureOpen() throws IOException {
459: if (parent == null) {
460: throw new IOException(
461: /* #ifdef VERBOSE_EXCEPTIONS */
462: /// skipped "Stream closed"
463: /* #endif */
464: );
465: }
466: }
467:
468: /**
469: * Writes the specified byte to this output stream.
470: * <p>
471: * Polling the native code is done here to allow for simple
472: * asynchronous native code to be written. Not all implementations
473: * work this way (they block in the native code) but the same
474: * Java code works for both.
475: *
476: * @param b the <code>byte</code>.
477: * @exception IOException if an I/O error occurs. In particular,
478: * an <code>IOException</code> may be thrown if the
479: * output stream has been closed.
480: */
481: synchronized public void write(int b) throws IOException {
482: ensureOpen();
483: while (true) {
484: int res = Protocol.writeByte(parent.handle, b);
485: if (res != 0) {
486: // IMPL_NOTE: should EOFException be thrown if write fails?
487: return;
488: }
489: }
490: }
491:
492: /**
493: * Writes <code>len</code> bytes from the specified byte array
494: * starting at offset <code>off</code> to this output stream.
495: * <p>
496: * Polling the native code is done here to allow for simple
497: * asynchronous native code to be written. Not all implementations
498: * work this way (they block in the native code) but the same
499: * Java code works for both.
500: *
501: * @param b the data.
502: * @param off the start offset in the data.
503: * @param len the number of bytes to write.
504: * @exception IOException if an I/O error occurs. In particular,
505: * an <code>IOException</code> is thrown if the output
506: * stream is closed.
507: */
508: synchronized public void write(byte b[], int off, int len)
509: throws IOException {
510: ensureOpen();
511: if (len == 0) {
512: return;
513: }
514:
515: // Check for array index out of bounds, and NullPointerException,
516: // so that the native code doesn't need to do it
517: int test = b[off] + b[off + len - 1];
518:
519: int n = 0;
520: while (true) {
521: n += Protocol.writeBuf(parent.handle, b, off + n, len - n);
522: if (n == len) {
523: break;
524: }
525: }
526: }
527:
528: /**
529: * Close the stream.
530: *
531: * @exception IOException if an I/O error occurs
532: */
533: public void close() throws IOException {
534: if (parent != null) {
535: ensureOpen();
536: parent.realClose();
537: parent.osopen = false;
538: parent = null;
539: }
540: }
541:
542: }
|