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.midp.io.j2me.serversocket;
028:
029: import java.io.IOException;
030: import java.io.InterruptedIOException;
031:
032: import javax.microedition.io.StreamConnection;
033: import javax.microedition.io.ServerSocketConnection;
034:
035: import com.sun.j2me.security.AccessController;
036: import com.sun.j2me.security.InterruptedSecurityException;
037:
038: import com.sun.midp.io.j2me.socket.ServerSocket;
039:
040: import com.sun.midp.io.Util;
041:
042: import com.sun.midp.midlet.MIDletSuite;
043: import com.sun.midp.midlet.MIDletStateHandler;
044:
045: import com.sun.midp.security.Permissions;
046: import com.sun.midp.security.SecurityToken;
047:
048: /**
049: * Implements server sockets for J2ME devices.
050: */
051: public class Socket implements ServerSocketConnection, ServerSocket {
052:
053: /** TCP server permission name. */
054: private static final String SERVER_PERMISSION_NAME = "javax.microedition.io.Connector.serversocket";
055:
056: /**
057: * Handle to native server socket object. This is set and get only by
058: * native code.
059: */
060: private int nativeHandle = -1;
061:
062: /** Flag to indicate connection is currently open. */
063: boolean connectionOpen = false;
064:
065: /**
066: * Privileged security token, initialized if privileged <code>open()</code>
067: * has been used, <code>null</code> otherwize.
068: */
069: private SecurityToken privilegedSecurityToken = null;
070:
071: /**
072: * Opens a port to listen on. This method relies on
073: * the MIDlet suite permissions before granting
074: * rights to use the inbound connection..
075: *
076: * @param port TCP to listen on. If less than or equal to zero, a
077: * port will be assigned automatically.
078: *
079: * @exception IOException if some other kind of I/O error occurs
080: * @exception SecurityException if the current MIDlet suite does not have
081: * permission to open a server socket
082: */
083: public void open(int port) throws IOException {
084: open(port, null);
085: }
086:
087: /**
088: * Opens a port with privileged security token.
089: *
090: * @param port TCP to listen on. If less than or equal to zero, a
091: * port will be assigned automatically.
092: * @param token the security token
093: *
094: * @exception IOException if some other kind of I/O error occurs
095: * @exception SecurityException if the token is invalid
096: */
097: public void open(int port, SecurityToken token) throws IOException {
098: int suiteId = MIDletSuite.UNUSED_SUITE_ID;
099: try {
100: MIDletStateHandler midletStateHandler;
101: MIDletSuite midletSuite;
102:
103: if (token != null) {
104: token.checkIfPermissionAllowed(Permissions.TCP_SERVER);
105: privilegedSecurityToken = token;
106: } else {
107: AccessController.checkPermission(
108: SERVER_PERMISSION_NAME, "TCP Server" + port);
109: }
110:
111: midletStateHandler = MIDletStateHandler
112: .getMidletStateHandler();
113: midletSuite = midletStateHandler.getMIDletSuite();
114:
115: if (midletSuite != null) {
116: suiteId = midletSuite.getID();
117: }
118: } catch (SecurityException e) {
119: close();
120:
121: if (e instanceof InterruptedSecurityException) {
122: throw new InterruptedIOException(
123: "Interrupted while trying to ask the user permission");
124: }
125:
126: throw e;
127: }
128:
129: openCommon(port, suiteId);
130: }
131:
132: /**
133: * Common implementation of opening a port.
134: *
135: * @param port TCP port to listen on
136: * @param suiteId id of the currently running midlet, or null if
137: * there is no currently running midlet
138: * @exception IOException if an I/O error occurs
139: */
140: private void openCommon(int port, int suiteId) throws IOException {
141: open0(port > 0 ? port : 0, suiteId);
142: connectionOpen = true;
143: }
144:
145: /**
146: * Checks if the connection is open.
147: *
148: * @exception IOException is thrown, if the stream is not open
149: */
150: void ensureOpen() throws IOException {
151: if (!connectionOpen) {
152: throw new IOException("Connection closed");
153: }
154: }
155:
156: /**
157: * Returns a connection that represents a server side
158: * socket connection.
159: * <p>
160: *
161: * @return a socket to communicate with a client.
162: *
163: * @exception IOException if an I/O error occurs when creating the
164: * input stream
165: */
166: synchronized public StreamConnection acceptAndOpen()
167: throws IOException {
168:
169: com.sun.midp.io.j2me.socket.Protocol con;
170:
171: ensureOpen();
172:
173: con = new com.sun.midp.io.j2me.socket.Protocol();
174:
175: accept0(con);
176:
177: con.open(privilegedSecurityToken);
178: return con;
179: }
180:
181: /**
182: * Gets the local address to which the socket is bound.
183: *
184: * <P>The host address(IP number) that can be used to connect to this
185: * end of the socket connection from an external system.
186: * Since IP addresses may be dynamically assigned, a remote application
187: * will need to be robust in the face of IP number reassignment.</P>
188: * <P> The local hostname (if available) can be accessed from
189: * <code> System.getProperty("microedition.hostname")</code>
190: * </P>
191: *
192: * @return the local address to which the socket is bound
193: * @exception IOException if the connection was closed
194: * @see ServerSocketConnection
195: */
196: public String getLocalAddress() throws IOException {
197: ensureOpen();
198: return getLocalAddress0();
199: }
200:
201: /**
202: * Returns the local port to which this socket is bound.
203: *
204: * @return the local port number to which this socket is connected
205: * @exception IOException if the connection was closed
206: * @see ServerSocketConnection
207: */
208: public int getLocalPort() throws IOException {
209: ensureOpen();
210: return getLocalPort0();
211: }
212:
213: /**
214: * Closes the connection.
215: *
216: * @exception IOException if an I/O error occurs when closing the
217: * connection
218: */
219: public void close() throws IOException {
220: connectionOpen = false;
221: privilegedSecurityToken = null;
222: close0();
223: }
224:
225: /**
226: * Opens a server socket connection on the given port. If successful,
227: * stores a handle directly into the nativeHandle field. If unsuccessful,
228: * throws an exception.
229: *
230: * @param port TCP port to listen for connections on
231: * @param suiteId ID of current midlet suite, or null if there
232: * is no current suite
233: *
234: * @exception IOException if some other kind of I/O error occurs
235: * or if reserved by another suite
236: */
237: private native void open0(int port, int suiteId) throws IOException;
238:
239: /**
240: * Closes the connection.
241: *
242: * @exception IOException if an I/O error occurs when closing the
243: * connection
244: */
245: private native void close0() throws IOException;
246:
247: /**
248: * Waits for an incoming TCP connection on server socket. The method
249: * blocks current thread till a connection is made.
250: * <p>
251: * The 'con' parameter must be a freshly created client socket connection
252: * object. When an incoming connection is accepted, the socket handle for
253: * the newly accepted connection is stored into this object directly from
254: * native code. This technique ensures that the acceptance of a new
255: * connection and the storing of the native handle are performed
256: * atomically.
257: *
258: * @param con the client socket connection object
259: *
260: * @exception IOException if an I/O error has occurred
261: */
262: private native void accept0(com.sun.midp.io.j2me.socket.Protocol con)
263: throws IOException;
264:
265: /**
266: * Native finalizer
267: */
268: private native void finalize();
269:
270: /**
271: * Gets the local IP number.
272: *
273: * @return the IP address as a dotted-quad <tt>String</tt>
274: */
275: private native String getLocalAddress0();
276:
277: /**
278: * Gets the local port to which this socket connection is bound.
279: *
280: * @return the local port number for this socket connection
281: */
282: private native int getLocalPort0();
283: }
|